最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot2.0整合ES5實(shí)現(xiàn)文章內(nèi)容搜索實(shí)戰(zhàn)

 更新時(shí)間:2018年01月03日 10:35:40   作者:泥瓦匠BYSocket  
這篇文章主要介紹了Spring Boot2.0整合ES5實(shí)現(xiàn)文章內(nèi)容搜索實(shí)戰(zhàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

一、文章內(nèi)容搜索思路

上一篇講了在怎么在 Spring Boot 2.0 上整合 ES 5 ,這一篇聊聊具體實(shí)戰(zhàn)。簡(jiǎn)單講下如何實(shí)現(xiàn)文章、問(wèn)答這些內(nèi)容搜索的具體實(shí)現(xiàn)。實(shí)現(xiàn)思路很簡(jiǎn)單:

  1. 基于「短語(yǔ)匹配」并設(shè)置最小匹配權(quán)重值
  2. 哪來(lái)的短語(yǔ),利用 IK 分詞器分詞
  3. 基于 Fiter 實(shí)現(xiàn)篩選
  4. 基于 Pageable 實(shí)現(xiàn)分頁(yè)排序

這里直接調(diào)用搜索的話,容易搜出不盡人意的東西。因?yàn)閮?nèi)容搜索關(guān)注內(nèi)容的連接性。所以這里處理方法比較 low ,希望多交流一起實(shí)現(xiàn)更好的搜索方法。就是通過(guò)分詞得到很多短語(yǔ),然后利用短語(yǔ)進(jìn)行短語(yǔ)精準(zhǔn)匹配。

ES 安裝 IK 分詞器插件很簡(jiǎn)單。第一步,在下載對(duì)應(yīng)版本 https://github.com/medcl/elasticsearch-analysis-ik/releases。第二步,在 elasticsearch-5.5.3/plugins 目錄下,新建一個(gè)文件夾 ik,把 elasticsearch-analysis-ik-5.5.3.zip 解壓后的文件拷貝到 elasticsearch-5.1.1/plugins/ik 目錄下。最后重啟 ES 即可。

二、搜索內(nèi)容分詞

安裝好 IK ,如何調(diào)用呢?

第一步,我這邊搜搜內(nèi)容會(huì)以 逗號(hào) 拼接傳入。所以會(huì)先將逗號(hào)分割

第二步,在搜索詞中加入自己本身,因?yàn)橛行┰~經(jīng)過(guò) ik 分詞后就沒(méi)了... 這是個(gè) bug

第三步,利用 AnalyzeRequestBuilder 對(duì)象獲取 IK 分詞后的返回值對(duì)象列表

第四步,優(yōu)化分詞結(jié)果,比如都為詞,則保留全部;有詞有字,則保留詞;只有字,則保留字

核心實(shí)現(xiàn)代碼如下:

  /**
   * 搜索內(nèi)容分詞
   */
  protected List<String> handlingSearchContent(String searchContent) {

    List<String> searchTermResultList = new ArrayList<>();
    // 按逗號(hào)分割,獲取搜索詞列表
    List<String> searchTermList = Arrays.asList(searchContent.split(SearchConstant.STRING_TOKEN_SPLIT));

    // 如果搜索詞大于 1 個(gè)字,則經(jīng)過(guò) IK 分詞器獲取分詞結(jié)果列表
    searchTermList.forEach(searchTerm -> {
      // 搜索詞 TAG 本身加入搜索詞列表,并解決 will 這種問(wèn)題
      searchTermResultList.add(searchTerm);
      // 獲取搜索詞 IK 分詞列表
      searchTermResultList.addAll(getIkAnalyzeSearchTerms(searchTerm));
    });

    return searchTermResultList;
  }

  /**
   * 調(diào)用 ES 獲取 IK 分詞后結(jié)果
   */
  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();

    // 循環(huán)賦值
    List<String> searchTermList = new ArrayList<>();
    ikTokenList.forEach(ikToken -> {
      searchTermList.add(ikToken.getTerm());
    });

    return handlingIkResultTerms(searchTermList);
  }

  /**
   * 如果分詞結(jié)果:洗發(fā)水(洗發(fā)、發(fā)水、洗、發(fā)、水)
   * - 均為詞,保留
   * - 詞 + 字,只保留詞
   * - 均為字,保留字
   */
  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;
  }

三、搜索查詢語(yǔ)句

構(gòu)造內(nèi)容枚舉對(duì)象,羅列需要搜索的字段,ContentSearchTermEnum 代碼如下:

import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum ContentSearchTermEnum {
  // 標(biāo)題
  TITLE("title"),
  // 內(nèi)容
  CONTENT("content");

  /**
   * 搜索字段
   */
  private String name;

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}

循環(huán)進(jìn)行「短語(yǔ)搜索匹配」搜索字段,然后并設(shè)置最低權(quán)重值為 1。核心代碼如下:

  /**
   * 構(gòu)造查詢條件
   */
  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);
  }

四、篩選條件

搜到東西不止,有時(shí)候需求是這樣的。需要在某個(gè)品類下搜索,比如電商需要在某個(gè) 品牌 下搜索商品。那么需要構(gòu)造一些 fitler 進(jìn)行篩選。對(duì)應(yīng) SQL 語(yǔ)句的 Where 下的 OR 和 AND 兩種語(yǔ)句。在 ES 中使用 filter 方法添加過(guò)濾。代碼如下:

  /**
   * 構(gòu)建篩選條件
   */
  private void buildFilterQuery(BoolQueryBuilder boolQueryBuilder, Integer type, String category) {
    // 內(nèi)容類型篩選
    if (type != null) {
      BoolQueryBuilder typeFilterBuilder = QueryBuilders.boolQuery();
      typeFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, type).lenient(true));
      boolQueryBuilder.filter(typeFilterBuilder);
    }

    // 內(nèi)容類別篩選
    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 中搜索呢?具體實(shí)現(xiàn)代碼很簡(jiǎn)單:

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

通過(guò)鏈?zhǔn)奖磉_(dá)式,兩個(gè) should 實(shí)現(xiàn)或,即 SQL 對(duì)應(yīng)的 OR 語(yǔ)句。通過(guò)兩個(gè) BoolQueryBuilder 實(shí)現(xiàn)與,即 SQL 對(duì)應(yīng)的 AND 語(yǔ)句。

五、分頁(yè)、排序條件

分頁(yè)排序代碼就很簡(jiǎn)單了:

 @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);

    // 構(gòu)建搜索短語(yǔ)
    String searchContent = contentSearchBean.getSearchContent();
    List<String> searchTermList = handlingSearchContent(searchContent);

    // 構(gòu)建查詢條件
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    buildMatchQuery(boolQueryBuilder, searchTermList);

    // 構(gòu)建篩選條件
    buildFilterQuery(boolQueryBuilder, contentSearchBean.getType(), contentSearchBean.getCategory());

    // 構(gòu)建分頁(yè)、排序條件
    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 對(duì)象,構(gòu)造分頁(yè)參數(shù)以及指定對(duì)應(yīng)的 排序字段、排序順序(DESC ASC)即可。

六、小結(jié)

這個(gè)思路比較簡(jiǎn)單。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java for循環(huán)的幾種用法分析

    Java for循環(huán)的幾種用法分析

    本篇文章小編為大家介紹,Java for循環(huán)的幾種用法分析。需要的朋友參考下
    2013-04-04
  • SpringBoot基于Redis實(shí)現(xiàn)生成全局唯一ID的方法

    SpringBoot基于Redis實(shí)現(xiàn)生成全局唯一ID的方法

    在項(xiàng)目中生成全局唯一ID有很多好處,生成全局唯一ID有助于提高系統(tǒng)的可用性、數(shù)據(jù)的完整性和安全性,同時(shí)也方便數(shù)據(jù)的管理和分析,所以本文給大家介紹了SpringBoot基于Redis實(shí)現(xiàn)生成全局唯一ID的方法,文中有詳細(xì)的代碼講解,需要的朋友可以參考下
    2023-12-12
  • Java實(shí)現(xiàn)LeetCode(1.兩數(shù)之和)

    Java實(shí)現(xiàn)LeetCode(1.兩數(shù)之和)

    這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(兩數(shù)之和),本文使用java采用多種發(fā)放實(shí)現(xiàn)了LeetCode的兩數(shù)之和題目,需要的朋友可以參考下
    2021-06-06
  • 解決springboot集成rocketmq關(guān)于tag的坑

    解決springboot集成rocketmq關(guān)于tag的坑

    這篇文章主要介紹了解決springboot集成rocketmq關(guān)于tag的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java如何將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫(kù)

    Java如何將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫(kù)

    這篇文章主要為大家詳細(xì)介紹了Java將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫(kù)的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 詳解Spring框架之基于Restful風(fēng)格實(shí)現(xiàn)的SpringMVC

    詳解Spring框架之基于Restful風(fēng)格實(shí)現(xiàn)的SpringMVC

    這篇文章主要介紹了詳解Spring框架之基于Restful風(fēng)格實(shí)現(xiàn)的SpringMVC,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Spring中@Autowired @Resource @Inject三個(gè)注解有什么區(qū)別

    Spring中@Autowired @Resource @Inject三個(gè)注解有什么區(qū)別

    在我們使用Spring框架進(jìn)行日常開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)使用@Autowired, @Resource, @Inject注解來(lái)進(jìn)行依賴注入,下面來(lái)介紹一下這三個(gè)注解有什么區(qū)別
    2023-03-03
  • Java獲取磁盤(pán)空間的兩種代碼示例

    Java獲取磁盤(pán)空間的兩種代碼示例

    這篇文章主要介紹了Java獲取磁盤(pán)空間的兩種代碼示例,沒(méi)什么事的時(shí)候可以拿來(lái)玩玩,需要的朋友參考下。
    2017-11-11
  • javax.validation自定義日期范圍校驗(yàn)注解操作

    javax.validation自定義日期范圍校驗(yàn)注解操作

    這篇文章主要介紹了javax.validation自定義日期范圍校驗(yàn)注解操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • 淺析Java中的SPI原理

    淺析Java中的SPI原理

    SPI:由調(diào)用方制定接口標(biāo)準(zhǔn),實(shí)現(xiàn)方來(lái)針對(duì)接口提供不同的實(shí)現(xiàn),SPI其實(shí)就是"為接口查找實(shí)現(xiàn)"的一種服務(wù)發(fā)現(xiàn)機(jī)制。本文將淺談一下SPI機(jī)制的原理,需要的可以參考一下
    2022-09-09

最新評(píng)論

广西| 晋宁县| 竹山县| 宕昌县| 巧家县| 海丰县| 太白县| 新兴县| 皋兰县| 汝城县| 徐州市| 蚌埠市| 大同市| 元阳县| 登封市| 商都县| 台湾省| 彰化市| 遵义市| 依兰县| 澎湖县| 红河县| 乌拉特前旗| 鄢陵县| 曲麻莱县| 三穗县| 佳木斯市| 琼海市| 东海县| 塔城市| 秭归县| 侯马市| 安乡县| 忻城县| 陕西省| 甘孜| 郸城县| 余庆县| 宕昌县| 南溪县| 临沧市|