91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot2.0整合ES5如何實現文章內容搜索

發布時間:2021-08-06 10:55:36 來源:億速云 閱讀:129 作者:小新 欄目:編程語言

小編給大家分享一下Spring Boot2.0整合ES5如何實現文章內容搜索,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

一、文章內容搜索思路

實現思路很簡單:

  1. 基于「短語匹配」并設置最小匹配權重值

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

  3. 基于 Fiter 實現篩選

  4. 基于 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;
@AllArgsConstructor
public 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)即可。

以上是“Spring Boot2.0整合ES5如何實現文章內容搜索”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

齐齐哈尔市| 连山| 龙口市| 漾濞| 卢氏县| 时尚| 东莞市| 泰州市| 互助| 江都市| 当雄县| 怀仁县| 桓台县| 渝中区| 锦州市| 丹阳市| 鹤庆县| 白沙| 富平县| 米林县| 新津县| 南宁市| 沂水县| 公主岭市| 射阳县| 阿拉尔市| 澳门| 健康| 武乡县| 忻城县| 东至县| 吉木乃县| 武夷山市| 陵川县| 尉氏县| 息烽县| 开原市| 松滋市| 环江| 鄂尔多斯市| 白城市|