Spring Boot 2.0 整合 ES 5 文章內容搜尋實戰

來源:互聯網
上載者:User

標籤:string   sql   UI   com   get   values   查詢語句   val   public   

本章內容

  1. 文章內容搜尋思路

  2. 搜尋內容分詞

  3. 搜尋查詢語句

  4. 篩選條件

  5. 分頁、排序條件

  6. 小結

 

一、文章內容搜尋思路

上一篇講了在怎麼在 Spring Boot 2.0 上整合 ES 5 ,這一篇聊聊具體實戰。簡單講下如何?文章、問答這些內容搜尋的具體實現。實現思路很簡單:

  • 基於「短語匹配」並設定最小匹配權重值

  • 哪來的短語,利用 IK 分詞器分詞

  • 基於 Fiter 實現篩選

  • 基於 Pageable 實現分頁排序

     

這裡直接調用搜尋的話,容易搜出不盡人意的東西。因為內容搜尋關注內容的串連性。所以這裡處理方法比較 low ,希望多交流一起實現更好的搜尋方法。就是通過分詞得到很多短語,然後利用短語進行短語精準匹配。

 

ES 安裝 IK 分詞器外掛程式很簡單。第一步,在下載對應版本 https://github.com/medcl/elasticsearch-analysis-ik/releases。第二步,在 elasticsearch-5.5.3/plugins 目錄下,建立一個檔案夾 ik,把 elasticsearch-analysis-ik-5.5.3.zip 解壓後的檔案拷貝到 elasticsearch-5.1.1/plugins/ik 目錄下。最後重啟 ES 即可。

 

二、搜尋內容分詞

 

安裝好 IK ,如何調用呢?

 

第一步,我這邊搜搜內容會以 逗號 拼接傳入。所以會先將逗號分割

 

第二步,在搜尋字詞中加入自己本身,因為有些詞經過 ik 分詞後就沒了... 這是個 bug

 

第三步,利用 AnalyzeRequestBuilder 對象擷取 IK 分詞後的傳回值對象列表

 

第四步,最佳化分詞結果,比如都為詞,則保留全部;有詞有字,則保留詞;只有字,則保留字

 

核心實現代碼如下:

   /**     * 搜尋內容分詞     */    protected List<String>      handlingSearchContent(String searchContent) {              List<String> searchTermResultList = new ArrayList<>();             // 按逗號分割,擷取搜尋字詞列表             List<String> searchTermList = Arrays.asList(searchContent.split(SearchConstant.STRING_TOKEN_SPLIT));              // 如果搜尋字詞大於 1 個字,則經過 IK 分詞器擷取分詞結果清單             searchTermList.forEach(searchTerm -> {                 // 搜尋字詞 TAG 本身加入搜尋字詞列表,並解決 will 這種問題                 searchTermResultList.add(searchTerm);                 // 擷取搜尋字詞 IK 分詞列表                 searchTermResultList.addAll(getIkAnalyzeSearchTerms(searchTerm));             });              return searchTermResultList;    }     /**     * 調用 ES 擷取 IK 分詞後結果     */    protected List<String>      getIkAnalyzeSearchTerms(String searchContent) {             AnalyzeRequestBuilder ikRequest = new AnalyzeRequestBuilder(elasticsearchTemplate.getClient(),                     AnalyzeAction.INSTANCE, SearchConstant.INDEX_NAME,      searchContent);             ikRequest.setTokenizer(SearchConstant.TOKENIZER_IK_MAX);             List<AnalyzeResponse.AnalyzeToken> ikTokenList =      ikRequest.execute().actionGet().getTokens();              // 迴圈賦值             List<String> searchTermList = new ArrayList<>();             ikTokenList.forEach(ikToken -> {                 searchTermList.add(ikToken.getTerm());             });              return handlingIkResultTerms(searchTermList);    }     /**     * 如果分詞結果:洗髮水(洗髮、發水、洗、發、水)     * - 均為詞,保留     * - 詞 + 字,只保留詞     * - 均為字,保留字     */    private List<String>      handlingIkResultTerms(List<String> searchTermList) {             Boolean isPhrase = false;             Boolean isWord = false;             for (String term : searchTermList) {                 if (term.length() > SearchConstant.SEARCH_TERM_LENGTH)      {                     isPhrase = true;                 } else {                     isWord = true;                 }             }              if (isWord & isPhrase) {                 List<String> phraseList = new ArrayList<>();                 searchTermList.forEach(term -> {                     if (term.length() > SearchConstant.SEARCH_TERM_LENGTH)      {                         phraseList.add(term);                     }                 });                 return phraseList;             }              return searchTermList;    }

三、搜尋查詢語句

 

構造內容枚舉對象,羅列需要搜尋的欄位,ContentSearchTermEnum 代碼如下:

import lombok.AllArgsConstructor; @AllArgsConstructorpublic enum ContentSearchTermEnum {     // 標題    TITLE("title"),    // 內容    CONTENT("content");     /**     * 搜尋欄位     */    private String      name;     public String      getName() {             return name;    }     public void      setName(String name) {             this.name = name;    } }

迴圈進行「短語搜尋匹配」搜尋欄位,然後並設定最低權重值為 1。核心代碼如下:

   /**     * 構造查詢條件     */    private void      buildMatchQuery(BoolQueryBuilder queryBuilder, List<String>      searchTermList) {             for (String searchTerm : searchTermList) {                 for (ContentSearchTermEnum searchTermEnum : ContentSearchTermEnum.values())      {                     queryBuilder.should(QueryBuilders.matchPhraseQuery(searchTermEnum.getName(),      searchTerm));                 }             }             queryBuilder.minimumShouldMatch(SearchConstant.MINIMUM_SHOULD_MATCH);    }

四、篩選條件

搜到東西不止,有時候需求是這樣的。需要在某個品類下搜尋,比如電商需要在某個 品牌 下搜尋商品。那麼需要構造一些 fitler 進行篩選。對應 SQL 陳述式的 Where 下的 OR 和 AND 兩種語句。在 ES 中使用 filter 方法添加過濾。代碼如下:

   /**     * 構建篩選條件     */    private void      buildFilterQuery(BoolQueryBuilder boolQueryBuilder, Integer type, String      category) {             // 內容類型篩選             if (type != null) {                 BoolQueryBuilder typeFilterBuilder = QueryBuilders.boolQuery();                 typeFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME,      type).lenient(true));                 boolQueryBuilder.filter(typeFilterBuilder);             }              // 內容類別篩選             if (!StringUtils.isEmpty(category)) {                 BoolQueryBuilder categoryFilterBuilder = QueryBuilders.boolQuery();                 categoryFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.CATEGORY_NAME,      category).lenient(true));                 boolQueryBuilder.filter(categoryFilterBuilder);             }    }

type 是大類,category 是小類,這樣就可以支援 大小類 篩選。但是如果需要在 type = 1 或者 type = 2 中搜尋呢?具體實現代碼很簡單:

typeFilterBuilder    .should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME,      1)    .should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME,      2)    .lenient(true));

通過鏈式運算式,兩個 should 實現或,即 SQL 對應的 OR 語句。通過兩個 BoolQueryBuilder 實現與,即 SQL 對應的 AND 語句。

 

五、分頁、排序條件

 

分頁排序代碼就很簡單了:

  @Override    public PageBean      searchContent(ContentSearchBean contentSearchBean) {              Integer pageNumber = contentSearchBean.getPageNumber();             Integer pageSize = contentSearchBean.getPageSize();              PageBean<ContentEntity> resultPageBean = new PageBean<>();             resultPageBean.setPageNumber(pageNumber);             resultPageBean.setPageSize(pageSize);              // 構建搜尋詞句             String searchContent = contentSearchBean.getSearchContent();             List<String> searchTermList =      handlingSearchContent(searchContent);              // 構建查詢條件             BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();             buildMatchQuery(boolQueryBuilder, searchTermList);              // 構建篩選條件             buildFilterQuery(boolQueryBuilder, contentSearchBean.getType(),      contentSearchBean.getCategory());              // 構建分頁、排序條件             Pageable pageable = PageRequest.of(pageNumber, pageSize);             if (!StringUtils.isEmpty(contentSearchBean.getOrderName())) {                 pageable = PageRequest.of(pageNumber, pageSize, Sort.Direction.DESC,      contentSearchBean.getOrderName());             }             SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable)                     .withQuery(boolQueryBuilder).build();              // 搜尋             LOGGER.info("\n ContentServiceImpl.searchContent() [" +      searchContent                     + "] \n DSL  = \n " +      searchQuery.getQuery().toString());             Page<ContentEntity> contentPage =      contentRepository.search(searchQuery);              resultPageBean.setResult(contentPage.getContent());             resultPageBean.setTotalCount((int) contentPage.getTotalElements());             resultPageBean.setTotalPage((int) contentPage.getTotalElements() /      resultPageBean.getPageSize() + 1);             return resultPageBean;    }

利用 Pageable 對象,構造分頁參數以及指定對應的 排序欄位、排序次序(DESC ASC)即可。

 

文章來源:http://mp.weixin.qq.com/s/ZoJzF9VpynUBSQWlJJjmEw

springboot視頻教程:http://www.roncoo.com/course/list.html?courseName=spring+boot

 

Spring Boot 2.0 整合 ES 5 文章內容搜尋實戰

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.