<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot操作ES進(jìn)行各種高級(jí)查詢(值得收藏)

          共 45383字,需瀏覽 91分鐘

           ·

          2021-03-14 17:58


          來源:cnblogs.com/keatsCoder/p/11341835.html

          SpringBoot整合ES

          創(chuàng)建SpringBoot項(xiàng)目,導(dǎo)入 ES 6.2.1 的 RestClient 依賴和 ES 依賴。在項(xiàng)目中直接引用 es-starter 的話會(huì)報(bào)容器初始化異常錯(cuò)誤,導(dǎo)致項(xiàng)目無法啟動(dòng)。如果有讀者解決了這個(gè)問題,歡迎留言交流

          <!-- ES 客戶端 -->
          <dependency>
              <groupId>org.elasticsearch.client</groupId>
              <artifactId>elasticsearch-rest-high-level-client</artifactId>
              <version>${elasticsearch.version}</version>
          </dependency>
          <!-- ES 版本 -->
          <dependency>
              <groupId>org.elasticsearch</groupId>
              <artifactId>elasticsearch</artifactId>
              <version>${elasticsearch.version}</version>
          </dependency>

          為容器定義 RestClient 對(duì)象

          /**
           * 在Spring容器中定義 RestClient 對(duì)象
           * @Author: keats_coder
           * @Version 1.0
           * */

          @Configuration
          public class ESConfig {
              @Value("${yunshangxue.elasticsearch.hostlist}")
              private String hostlist; // 127.0.0.1:9200

              @Bean // 高版本客戶端
              public RestHighLevelClient restHighLevelClient() {
                  // 解析 hostlist 配置信息。假如以后有多個(gè),則需要用 , 分開
                  String[] split = hostlist.split(",");
                  // 創(chuàng)建 HttpHost 數(shù)組,其中存放es主機(jī)和端口的配置信息
                  HttpHost[] httpHostArray = new HttpHost[split.length];
                  for (int i = 0; i < split.length; i++) {
                      String item = split[i];
                      httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
                  }
                  // 創(chuàng)建RestHighLevelClient客戶端
                  return new RestHighLevelClient(RestClient.builder(httpHostArray));
              }

              // 項(xiàng)目主要使用 RestHighLevelClient,對(duì)于低級(jí)的客戶端暫時(shí)不用
              @Bean
              public RestClient restClient() {
                  // 解析hostlist配置信息
                  String[] split = hostlist.split(",");
                  // 創(chuàng)建HttpHost數(shù)組,其中存放es主機(jī)和端口的配置信息
                  HttpHost[] httpHostArray = new HttpHost[split.length];
                  for (int i = 0; i < split.length; i++) {
                      String item = split[i];
                      httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
                  }
                  return RestClient.builder(httpHostArray).build();
              }
          }

          在 yml 文件中配置 eshost

          yunshangxue:
            elasticsearch:
              hostlist: ${eshostlist:127.0.0.1:9200}

          調(diào)用相關(guān) API 執(zhí)行操作

          • 創(chuàng)建操作索引的對(duì)象
          • 構(gòu)建操作索引的請(qǐng)求
          • 調(diào)用對(duì)象的相關(guān)API發(fā)送請(qǐng)求
          • 獲取響應(yīng)消息
          /**
           * 刪除索引庫
           */

          @Test
          public void testDelIndex() throws IOException {
              // 操作索引的對(duì)象
              IndicesClient indices = client.indices();
              // 刪除索引的請(qǐng)求
              DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("ysx_course");
              // 刪除索引
              DeleteIndexResponse response = indices.delete(deleteIndexRequest);
              // 得到響應(yīng)
              boolean b = response.isAcknowledged();
              System.out.println(b);
          }

          創(chuàng)建索引, 步驟和刪除類似,需要注意的是刪除的時(shí)候需要指定 ES 庫分片的數(shù)量和副本的數(shù)量,并且在創(chuàng)建索引的時(shí)候可以將映射一起指定了。代碼如下

          public void testAddIndex() throws IOException {
              // 操作索引的對(duì)象
              IndicesClient indices = client.indices();
              // 創(chuàng)建索引的請(qǐng)求
              CreateIndexRequest request = new CreateIndexRequest("ysx_course");
              request.settings(Settings.builder().put("number_of_shards""1").put("number_of_replicas""0"));
              // 創(chuàng)建映射
              request.mapping("doc""{\n" +
                      "                \"properties\": {\n" +
                      "                    \"description\": {\n" +
                      "                        \"type\": \"text\",\n" +
                      "                        \"analyzer\": \"ik_max_word\",\n" +
                      "                        \"search_analyzer\": \"ik_smart\"\n" +
                      "                    },\n" +
                      "                    \"name\": {\n" +
                      "                        \"type\": \"text\",\n" +
                      "                        \"analyzer\": \"ik_max_word\",\n" +
                      "                        \"search_analyzer\": \"ik_smart\"\n" +
                      "                    },\n" +
                      "\"pic\":{                    \n" +
                      "\"type\":\"text\",                        \n" +
                      "\"index\":false                        \n" +
                      "},                    \n" +
                      "                    \"price\": {\n" +
                      "                        \"type\": \"float\"\n" +
                      "                    },\n" +
                      "                    \"studymodel\": {\n" +
                      "                        \"type\": \"keyword\"\n" +
                      "                    },\n" +
                      "                    \"timestamp\": {\n" +
                      "                        \"type\": \"date\",\n" +
                      "                        \"format\": \"yyyy-MM‐dd HH:mm:ss||yyyy‐MM‐dd||epoch_millis\"\n" +
                      "                    }\n" +
                      "                }\n" +
                      "            }", XContentType.JSON);


              // 執(zhí)行創(chuàng)建操作
              CreateIndexResponse response = indices.create(request);
              // 得到響應(yīng)
              boolean b = response.isAcknowledged();
              System.out.println(b);
          }

          Java API操作ES

          準(zhǔn)備數(shù)據(jù)環(huán)境

          創(chuàng)建索引:ysx_course

          創(chuàng)建映射:

          PUT http://localhost:9200/ysx_course/doc/_mapping

          {
              "properties": {
                  "description": { // 課程描述
                      "type""text", // String text 類型
                      "analyzer""ik_max_word", // 存入的分詞模式:細(xì)粒度
                      "search_analyzer""ik_smart" // 查詢的分詞模式:粗粒度
                  },
                  "name": { // 課程名稱
                      "type""text",
                      "analyzer""ik_max_word",
                      "search_analyzer""ik_smart"
                  },
                  "pic":{ // 圖片地址
                      "type":"text"
                      "index":false // 地址不用來搜索,因此不為它構(gòu)建索引
                  },
                  "price": { // 價(jià)格
                   "type""scaled_float", // 有比例浮點(diǎn)
                   "scaling_factor": 100 // 比例因子 100
                  },
                  "studymodel": {
                      "type""keyword" // 不分詞,全關(guān)鍵字匹配
                  },
                  "timestamp": {
                      "type""date",
                      "format""yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
                  }
              }
          }

          加入原始數(shù)據(jù):

          POST http://localhost:9200/ysx_course/doc/1

          {
           "name""Bootstrap開發(fā)",
           "description""Bootstrap是由Twitter推出的一個(gè)前臺(tái)頁面開發(fā)框架,是一個(gè)非常流行的開發(fā)框架,此框架集成了多種頁面效果。此開發(fā)框架包含了大量的CSS、JS程序代碼,可以幫助開發(fā)者(尤其是不擅長(zhǎng)頁面開發(fā)的程序人員)輕松的實(shí)現(xiàn)一個(gè)不受瀏覽器限制的精美界面效果。",
           "studymodel""201002",
           "price":38.6,
           "timestamp":"2018-04-25 19:11:35",
           "pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
          }

          DSL搜索

          DSL(Domain Specific Language)是ES提出的基于json的搜索方式,在搜索時(shí)傳入特定的json格式的數(shù)據(jù)來完成不同的搜索需求。DSL比URI搜索方式功能強(qiáng)大,在項(xiàng)目中建議使用DSL方式來完成搜索。

          查詢?nèi)?span style="display: none;">

          原本我們想要查詢?nèi)康脑挘枰褂?GET 請(qǐng)求發(fā)送 _search 命令,如今使用 DSL 方式搜索,可以使用 POST 請(qǐng)求,并在請(qǐng)求體中設(shè)置 JSON 字符串來構(gòu)建查詢條件

          POST http://localhost:9200/ysx_course/doc/_search

          請(qǐng)求體 JSON


              "query": {
                  "match_all": {} // 查詢?nèi)?br>    },
              "_source" : ["name","studymodel"] // 查詢結(jié)果包括 課程名 + 學(xué)習(xí)模式兩個(gè)映射
          }

          具體的測(cè)試方法如下:過程比較繁瑣,好在條理還比較清晰

          // 搜索全部記錄
          @Test
          public void testSearchAll() throws IOException, ParseException {
              // 搜索請(qǐng)求對(duì)象
              SearchRequest searchRequest = new SearchRequest("ysx_course");
              // 指定類型
              searchRequest.types("doc");
              // 搜索源構(gòu)建對(duì)象
              SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
              // 搜索方式
              // matchAllQuery搜索全部
              searchSourceBuilder.query(QueryBuilders.matchAllQuery());
              // 設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
              searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
              // 向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
              searchRequest.source(searchSourceBuilder);
              // 執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
              SearchResponse searchResponse = client.search(searchRequest);
              // 搜索結(jié)果
              SearchHits hits = searchResponse.getHits();
              // 匹配到的總記錄數(shù)
              long totalHits = hits.getTotalHits();
              // 得到匹配度高的文檔
              SearchHit[] searchHits = hits.getHits();
              // 日期格式化對(duì)象
              SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              for(SearchHit hit:searchHits){
                  // 文檔的主鍵
                  String id = hit.getId();
                  // 源文檔內(nèi)容
                  Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                  String name = (String) sourceAsMap.get("name");
                  // 由于前邊設(shè)置了源文檔字段過慮,這時(shí)description是取不到的
                  String description = (String) sourceAsMap.get("description");
                  // 學(xué)習(xí)模式
                  String studymodel = (String) sourceAsMap.get("studymodel");
                  // 價(jià)格
                  Double price = (Double) sourceAsMap.get("price");
                  // 日期
                  Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
                  System.out.println(name);
                  System.out.println(studymodel);
                  System.out.println("你看不見我,看不見我~" + description);
                  System.out.println(price);
              }

          }

          坑:

          執(zhí)行過程中遇到的問題:不能對(duì)這個(gè)值進(jìn)行初始化,導(dǎo)致 Spring 容器無法初始化

          Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'yunshangxue.elasticsearch.hostlist' in value "${yunshangxue.elasticsearch.hostlist}"

          通過檢查 target 目錄發(fā)現(xiàn),生成的 target 文件包中沒有將 yml 配置文件帶過來... 仔細(xì)對(duì)比發(fā)現(xiàn),我的項(xiàng)目竟然變成了一個(gè)不是 Maven 的項(xiàng)目。重新使用 IDEA 導(dǎo)入 Mavaen 工程之后便能正常運(yùn)行了。

          推薦:Java面試練題寶典

          分頁查詢

          我們來 look 一下 ES 的分頁查詢參數(shù):


              // from 起始索引
              // size 每頁顯示的條數(shù)
              "from" : 0, "size" : 1,
              "query": {
                 "match_all": {}
               },
              "_source" : ["name","studymodel"]
          }

          通過查詢結(jié)果可以發(fā)現(xiàn),我們?cè)O(shè)置了分頁參數(shù)之后, hits.total 仍然是 3,表示它找到了 3 條數(shù)據(jù),而按照分頁規(guī)則,它只會(huì)返回一條數(shù)據(jù),因此 hits.hits 里面只有一條數(shù)據(jù)。這也符合我們的業(yè)務(wù)規(guī)則,在查詢前端頁面顯示總共的條數(shù)和當(dāng)前的數(shù)據(jù)。

          由此,我們就可以通過 Java API 來構(gòu)建查詢條件了:對(duì)上面查詢?nèi)康拇a進(jìn)行如下改造:

          // 搜索源構(gòu)建對(duì)象
          SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
          int page = 2// 頁碼
          int size = 1// 每頁顯示的條數(shù)
          int index = (page - 1) * size;
          searchSourceBuilder.from(index);
          searchSourceBuilder.size(1);
          // 搜索方式
          // matchAllQuery搜索全部
          searchSourceBuilder.query(QueryBuilders.matchAllQuery());

          精確查詢 TermQuery

          Term Query為精確查詢,在搜索時(shí)會(huì)整體匹配關(guān)鍵字,不再將關(guān)鍵字分詞

          例如:

          {
              "query": {
               "term": { // 查詢的方式為 term 精確查詢
                "name""spring" // 查詢的字段為 name 關(guān)鍵字是 spring
               }
              },
              "_source": [
                  "name",
                  "studymodel"
              ]
          }

          此時(shí)查詢的結(jié)果是:

           "hits": [
               {
                   "_index""ysx_course",
                   "_type""doc",
                   "_id""3",
                   "_score": 0.9331132,
                   "_source": {
                       "studymodel""201001",
                       "name""spring開發(fā)基礎(chǔ)"
                   }
               }
           ]

          查詢到了上面這條數(shù)據(jù),因?yàn)?spring開發(fā)基礎(chǔ) 分完詞后是 spring 開發(fā) 基礎(chǔ) ,而查詢關(guān)鍵字是 spring 不分詞,這樣當(dāng)然可以匹配到這條記錄,但是當(dāng)我們修改關(guān)鍵字為 spring開發(fā),按照往常的查詢方法,也是可以查詢到的。但是 term 不一樣,它不會(huì)對(duì)關(guān)鍵字分詞。結(jié)果可想而知是查詢不到的

          JavaAPI如下:

          // 搜索方式
          // termQuery 精確查詢
          searchSourceBuilder.query(QueryBuilders.termQuery("studymodel""201002"));

          根據(jù) ID 查詢:

          根據(jù) ID 精確查詢和根據(jù)其他條件精確查詢是一樣的,不同的是 id 字段前面有一個(gè)下劃線注意寫上

          searchSourceBuilder.query(QueryBuilders.termQuery("_id""1"));

          但是,當(dāng)一次查詢多個(gè) ID 時(shí),相應(yīng)的 API 也應(yīng)該改變,使用 termsQuery 而不是 termQuery。多了一個(gè) s

          全文檢索 MatchQuery

          MatchQuery 即全文檢索,會(huì)對(duì)關(guān)鍵字進(jìn)行分詞后匹配詞條。

          query:搜索的關(guān)鍵字,對(duì)于英文關(guān)鍵字如果有多個(gè)單詞則中間要用半角逗號(hào)分隔,而對(duì)于中文關(guān)鍵字中間可以用逗號(hào)分隔也可以不用

          operator:設(shè)置查詢的結(jié)果取交集還是并集,并集用 or, 交集用 and

          {
              "query": {
                  "match": {
                      "description": {
                          "query""spring開發(fā)",
                          "operator""or"
                      }
                  }
              }
          }

          有時(shí),我們需要設(shè)定一個(gè)量化的表達(dá)方式,例如查詢 spring開發(fā)基礎(chǔ),這三個(gè)詞條。我們需求是至少匹配兩個(gè)詞條,這時(shí) operator 屬性就不能滿足要求了,ES 還提供了另外一個(gè)屬性:minimum_should_match 用一個(gè)百分?jǐn)?shù)來設(shè)定應(yīng)該有多少個(gè)詞條滿足要求。例如查詢:

          “spring開發(fā)框架”會(huì)被分為三個(gè)詞:spring、開發(fā)、框架

          設(shè)置"minimum_should_match": "80%"表示,三個(gè)詞在文檔的匹配占比為80%,即3*0.8=2.4,向下取整得2,表示至少有兩個(gè)詞在文檔中要匹配成功。

          推薦:Java面試練題寶典

          JavaAPI

          通過 matchQuery.minimumShouldMatch 的方式來設(shè)置條件

          // matchQuery全文檢索
          searchSourceBuilder.query(QueryBuilders.matchQuery("description""Spring開發(fā)框架").minimumShouldMatch("70%"));

          多字段聯(lián)合搜索 MultiQuery

          上面的 MatchQuery 有一個(gè)短板,假如用戶輸入了某關(guān)鍵字,我們?cè)诓檎业臅r(shí)候并不知道他輸入的是 name 還是 description,這時(shí)我們用什么都不合適,而 MultiQuery 的出現(xiàn)解決了這個(gè)問題,他可以通過 fields 屬性來設(shè)置多個(gè)域聯(lián)合查找:具體用法如下

          {
              "query": {
                  "multi_match": {
                      "query""Spring開發(fā)",
                      "minimum_should_match""70%",
                      "fields": ["name""description"]
                  }
              }
          }

          JavaAPI

          searchSourceBuilder.query(QueryBuilders.multiMatchQuery("Spring開發(fā)框架""name""description").minimumShouldMatch("70%"));

          提升 boost

          在多域聯(lián)合查詢的時(shí)候,可以通過 boost 來設(shè)置某個(gè)域在計(jì)算得分時(shí)候的比重,比重越高的域當(dāng)他符合條件時(shí)計(jì)算的得分越高,相應(yīng)的該記錄也更靠前。通過在 fields 中給相應(yīng)的字段用 ^權(quán)重倍數(shù)來實(shí)現(xiàn)

          "fields": ["name^10""description"]

          上面的代碼表示給 name 字段提升十倍權(quán)重,查詢到的結(jié)果:

          {
              "_index""ysx_course",
              "_type""doc",
              "_id""3",
              "_score": 13.802518, // 可以清楚的發(fā)現(xiàn),得分竟然是 13 了
              "_source": {
                  "name""spring開發(fā)基礎(chǔ)",
                  "description""spring 在java領(lǐng)域非常流行,java程序員都在用。",
                  "studymodel""201001",
                  "price": 88.6,
                  "timestamp""2018-02-24 19:11:35",
                  "pic""group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
              }
          },

          而在 Java 中,仍然可以通過鏈?zhǔn)骄幊虂韺?shí)現(xiàn)

          searchSourceBuilder.query(QueryBuilders.multiMatchQuery("Spring開發(fā)框架""name""description").field("name", 10)); // 設(shè)置 name 10倍權(quán)重

          布爾查詢 BoolQuery

          如果我們既要對(duì)一些字段進(jìn)行分詞查詢,同時(shí)要對(duì)另一些字段進(jìn)行精確查詢,就需要使用布爾查詢來實(shí)現(xiàn)了。布爾查詢對(duì)應(yīng)于Lucene的BooleanQuery查詢,實(shí)現(xiàn)將多個(gè)查詢組合起來,有三個(gè)可選的參數(shù):

          must:文檔必須匹配must所包括的查詢條件,相當(dāng)于 “AND”

          should:文檔應(yīng)該匹配should所包括的查詢條件其中的一個(gè)或多個(gè),相當(dāng)于 "OR"

          must_not:文檔不能匹配must_not所包括的該查詢條件,相當(dāng)于“NOT”

          {
              "query": {
                  "bool": { // 布爾查詢
                      "must": [ // 查詢條件 must 表示數(shù)組中的查詢方式所規(guī)定的條件都必須滿足
                          {
                              "multi_match": {
                                  "query""spring框架",
                                  "minimum_should_match""50%",
                                  "fields": [
                                      "name^10",
                                      "description"
                                  ]
                              }
                          },
                          {
                              "term": {
                                  "studymodel""201001"
                              }
                          }
                      ]
                  }
              }
          }

          JavaAPI

          // 搜索方式
          // 首先構(gòu)造多關(guān)鍵字查詢條件
          MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("Spring開發(fā)框架""name""description").field("name"10);
          // 然后構(gòu)造精確匹配查詢條件
          TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("studymodel""201002");
          // 組合兩個(gè)條件,組合方式為 must 全滿足
          BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
          boolQueryBuilder.must(matchQueryBuilder);
          boolQueryBuilder.must(termQueryBuilder);
          // 將查詢條件封裝給查詢對(duì)象
          searchSourceBuilder.query(boolQueryBuilder);

          過濾器

          定義過濾器查詢,是在原本查詢結(jié)果的基礎(chǔ)上對(duì)數(shù)據(jù)進(jìn)行篩選,因此省略了重新計(jì)算的分的步驟,效率更高。并且方便緩存。推薦盡量使用過慮器去實(shí)現(xiàn)查詢或者過慮器和查詢共同使用,過濾器在布爾查詢中使用,下邊是在搜索結(jié)果的基礎(chǔ)上進(jìn)行過濾:

          {
              "query": {
                  "bool": {
                      "must": [
                          {
                              "multi_match": {
                                  "query""spring框架",
                                  "minimum_should_match""50%",
                                  "fields": [
                                      "name^10",
                                      "description"
                                  ]
                              }
                          }
                      ],
                      "filter": [
                          {
                              // 過濾條件:studymodel 必須是 201001
                              "term": {"studymodel""201001"}
                          },
                          {
                              // 過濾條件:價(jià)格 >=60 <=100
                              "range": {"price": {"gte": 60,"lte": 100}}
                          }
                      ]
                  }
              }
          }

          注意:range和term一次只能對(duì)一個(gè)Field設(shè)置范圍過慮。

          JavaAPI

          // 首先構(gòu)造多關(guān)鍵字查詢條件
          MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("Spring框架""name""description").field("name"10);
          // 添加條件到布爾查詢
          BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
          boolQueryBuilder.must(matchQueryBuilder);
          // 通過布爾查詢來構(gòu)造過濾查詢
          boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel""201001"));
          boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100));
          // 將查詢條件封裝給查詢對(duì)象
          searchSourceBuilder.query(boolQueryBuilder);

          排序

          我們可以在查詢的結(jié)果上進(jìn)行二次排序,支持對(duì) keyword、date、float 等類型添加排序,text類型的字段不允許排序。排序使用的 JSON 格式如下:

          {
              "query": {
                  "bool": {
                      "filter": [
                          {
                              "range": {
                                  "price": {
                                      "gte": 0,
                                      "lte": 100
                                  }
                              }
                          }
                      ]
                  }
              },
              "sort": [ // 注意這里排序是寫在 query key 的外面的。這就表示它的API也不是布爾查詢提供
                  {
                      "studymodel""desc" // 對(duì) studymodel(keyword)降序
                  },
                  {
                      "price""asc" // 對(duì) price(double)升序
                  }
              ]
          }

          由上面的 JSON 數(shù)據(jù)可以發(fā)現(xiàn),排序所屬的 API 是和 query 評(píng)級(jí)的,因此在調(diào)用 API 時(shí)也應(yīng)該選擇對(duì)應(yīng)的 SearchSourceBuilder 對(duì)象

          // 排序查詢
          @Test
          public void testSort() throws IOException, ParseException {
              // 搜索請(qǐng)求對(duì)象
              SearchRequest searchRequest = new SearchRequest("ysx_course");
              // 指定類型
              searchRequest.types("doc");
              // 搜索源構(gòu)建對(duì)象
              SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
              // 搜索方式
              // 添加條件到布爾查詢
              BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
              // 通過布爾查詢來構(gòu)造過濾查詢
              boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100));
              // 將查詢條件封裝給查詢對(duì)象
              searchSourceBuilder.query(boolQueryBuilder);
              // 向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
              searchRequest.source(searchSourceBuilder);
              
              // 設(shè)置排序規(guī)則
              searchSourceBuilder.sort("studymodel", SortOrder.DESC); // 第一排序規(guī)則
              searchSourceBuilder.sort("price", SortOrder.ASC); // 第二排序規(guī)則
              
              // 執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
              SearchResponse searchResponse = client.search(searchRequest);
              // 搜索結(jié)果
              SearchHits hits = searchResponse.getHits();
              // 匹配到的總記錄數(shù)
              long totalHits = hits.getTotalHits();
              // 得到匹配度高的文檔
              SearchHit[] searchHits = hits.getHits();
              // 日期格式化對(duì)象
              soutData(searchHits);
          }

          高亮顯示

          高亮顯示可以將搜索結(jié)果一個(gè)或多個(gè)字突出顯示,以便向用戶展示匹配關(guān)鍵字的位置。

          推薦:Java面試練題寶典

          高亮三要素:高亮關(guān)鍵字、高亮前綴、高亮后綴

          {
              "query": {
                  "bool": {
                      "must": [
                          {
                              "multi_match": {
                                  "query""開發(fā)框架",
                                  "minimum_should_match""50%",
                                  "fields": [
                                      "name^10",
                                      "description"
                                  ],
                                  "type""best_fields"
                              }
                          }
                      ]
                  }
              },
              "sort": [
                  {
                      "price""asc"
                  }
              ],
              "highlight": {
                  "pre_tags": [
                      "<em>"
                  ],
                  "post_tags": [
                      "</em>"
                  ],
                  "fields": {
                      "name": {},
                      "description": {}
                  }
              }
          }

          查詢結(jié)果的數(shù)據(jù)如下:

          Java 代碼如下,注意到上面的 JSON 數(shù)據(jù), highlight 和 sort 和 query 依然是同級(jí)的,所以也需要用 SearchSourceBuilder 對(duì)象來設(shè)置到搜索條件中

          // 高亮查詢
          @Test
          public void testHighLight() throws IOException, ParseException {
              // 搜索請(qǐng)求對(duì)象
              SearchRequest searchRequest = new SearchRequest("ysx_course");
              // 指定類型
              searchRequest.types("doc");
              // 搜索源構(gòu)建對(duì)象
              SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
              // 搜索方式
              // 首先構(gòu)造多關(guān)鍵字查詢條件
              MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("Spring框架""name""description").field("name"10);
              // 添加條件到布爾查詢
              BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
              boolQueryBuilder.must(matchQueryBuilder);
              // 通過布爾查詢來構(gòu)造過濾查詢
              boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100));
              // 將查詢條件封裝給查詢對(duì)象
              searchSourceBuilder.query(boolQueryBuilder);
           // ***********************
              
              // 高亮查詢
              HighlightBuilder highlightBuilder = new HighlightBuilder();
              highlightBuilder.preTags("<em>"); // 高亮前綴
              highlightBuilder.postTags("</em>"); // 高亮后綴
              highlightBuilder.fields().add(new HighlightBuilder.Field("name")); // 高亮字段
              // 添加高亮查詢條件到搜索源
              searchSourceBuilder.highlighter(highlightBuilder);
              
           // ***********************
              
              // 設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
              searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
              // 向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
              searchRequest.source(searchSourceBuilder);
              // 執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
              SearchResponse searchResponse = client.search(searchRequest);
              // 搜索結(jié)果
              SearchHits hits = searchResponse.getHits();
              // 匹配到的總記錄數(shù)
              long totalHits = hits.getTotalHits();
              // 得到匹配度高的文檔
              SearchHit[] searchHits = hits.getHits();
              // 日期格式化對(duì)象
              soutData(searchHits);
          }

          根據(jù)查詢結(jié)果的數(shù)據(jù)結(jié)構(gòu)來獲取高亮的數(shù)據(jù),替換原有的數(shù)據(jù):

          private void soutData(SearchHit[] searchHits) throws ParseException {
              SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              for (SearchHit hit : searchHits) {
                  // 文檔的主鍵
                  String id = hit.getId();
                  // 源文檔內(nèi)容
                  Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                  String name = (String) sourceAsMap.get("name");

                  // 獲取高亮查詢的內(nèi)容。如果存在,則替換原來的name
                  Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                  if( highlightFields != null ){
                      HighlightField nameField = highlightFields.get("name");
                      if(nameField!=null){
                          Text[] fragments = nameField.getFragments();
                          StringBuffer stringBuffer = new StringBuffer();
                          for (Text str : fragments) {
                              stringBuffer.append(str.string());
                          }
                          name = stringBuffer.toString();
                      }
                  }

                  // 由于前邊設(shè)置了源文檔字段過慮,這時(shí)description是取不到的
                  String description = (String) sourceAsMap.get("description");
                  // 學(xué)習(xí)模式
                  String studymodel = (String) sourceAsMap.get("studymodel");
                  // 價(jià)格
                  Double price = (Double) sourceAsMap.get("price");
                  // 日期
                  Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
                  System.out.println(name);
                  System.out.println(id);
                  System.out.println(studymodel);
                  System.out.println("你看不見我,看不見我~" + description);
                  System.out.println(price);
              }
          }

          往期資源  需要請(qǐng)自取

          真香警告!Alibaba珍藏版mybatis手寫文檔,刷起來

          臥槽!字節(jié)跳動(dòng)《算法中文手冊(cè)》火了,完整版 PDF 開放下載!

          字節(jié)跳動(dòng)總結(jié)的設(shè)計(jì)模式 PDF 火了,完整版開放下載!

          堪稱神級(jí)的Spring Boot手冊(cè),從基礎(chǔ)入門到實(shí)戰(zhàn)進(jìn)階

          臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久爱成人 | 无码人妻精品一区二区三区99仓 | 特黄AAAAAAA片免费看 | 91站街农村熟女露脸 | 日韩在线偷拍 |