Springboot整合Elasticsearch實現實時搜索

Springboot整合Elasticsearch實現實時搜索

前端頁面採用的是github上看到的頁面使用Vue實現,GitHub原址:https://github.com/lavyun/vue-demo-search ,後臺頁面採用springboot+es實現。

Springboot項目構建省略,不會的朋友參考。(springboot入門
Elasticsearch安裝步驟省略,沒安裝的參考。(Elasticsearch環境搭建和介紹(Windows)
Vue項目構建略過。( Vue-cli 快速構建Vue項目

創建SpringBoot 項目

首先新建一個SpringBoot項目,再進行Elasticsearch的整合實現搜索。
  1. pom.xml
	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>aliyunmaven</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
  1. application.yml
server:
  port: 8888
spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: 192.168.43.238:9300		#ip地址填寫自己的
  jackson:
    default-property-inclusion: non_null		#如果是空值則不返回

  1. 索引與查詢實例
@Data
@Document(indexName = "goodscat", type = "docs", shards = 1, replicas = 0)
public class Goods {

    @Id
    private Long cid;
	// 所有需要被搜索的信息,包含標題,分類,甚至品牌
    @Field(type = FieldType.Keyword, index = true, analyzer = "ik_max_word")
    private String name;	//分類名稱,
    private String isParent;
    private String parentId;
    private Long level;
    private String pathid;
}

Spring Data通過註解來聲明字段的映射屬性,上面三個註解代表的意思爲:

  • @Document 作用在類,標記實體類爲文檔對象,一般有兩個屬性

    • indexName:對應索引庫名稱

    • type:對應在索引庫中的類型

    • shards:分片數量,默認5

  • @Id 作用在成員變量,標記一個字段作爲id主鍵

  • @Field 作用在成員變量,標記爲文檔的字段,並指定字段映射屬性:

    • type:字段類型,是枚舉:FieldType,可以是text、long、short、date、integer、object等
    • text:存儲數據時候,會自動分詞,並生成索引
    • keyword:存儲數據時候,不會分詞建立索引
    • Numerical:數值類型,分兩類
      • 基本數據類型:long、interger、short、byte、double、float、half_float
      • 浮點數的高精度類型:scaled_float
        • 需要指定一個精度因子,比如10或100。elasticsearch會把真實值乘以這個因子後存儲,取出時再還原。
    • Date:日期類型
      • elasticsearch可以對日期格式化爲字符串存儲,但是建議我們存儲爲毫秒值,存儲爲long,節省空間。
  • index:是否索引,布爾類型,默認是true

  • store:是否存儲,布爾類型,默認是false

  • analyzer:分詞器名稱,這裏的ik_max_word即使用ik分詞器

4. 創建搜索配置類
public class SearchRequest {
    private String key;// 搜索條件

    private Integer page;// 當前頁

    private static final Integer DEFAULT_SIZE = 10;// 每頁大小,不從頁面接收,而是固定大小
    private static final Integer DEFAULT_PAGE = 1;// 默認頁

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Integer getPage() {
        if(page == null){
            return DEFAULT_PAGE;
        }
        // 獲取頁碼時做一些校驗,不能小於1
        return Math.max(DEFAULT_PAGE, page);
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getSize() {
        return DEFAULT_SIZE;
    }
}
  1. ElasticsearchRepository創建

dao層只需繼承ElasticsearchRepository類。其中主要的方法就是 save、delete和search,其中save方法相當如insert和update,沒有就新增,有就覆蓋。delete方法主要就是刪除數據以及索引庫。至於search就是查詢了。

package com.demo.elasticsearch.repository;

import com.demo.elasticsearch.pojo.Goods;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {

}
  1. service實現層(代碼只有搜索的實現,數據在測試類中已經添加完成了,這裏只做查詢)
@Slf4j
@Service
public class SearchServiceImpl implements SearchService {


    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private ElasticsearchTemplate template;

    @Override
    public PageResult<Goods> search(SearchRequest request) {
    	//分頁
        int page = request.getPage() - 1;
        int size = request.getSize();

        // 定義高亮字段
        HighlightBuilder.Field titleField = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
        //創建查詢構建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //結果過濾,只查詢cid,name字段
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"cid", "name"}, null));
        //分頁
        queryBuilder.withPageable(PageRequest.of(page, size));
        //過濾
        queryBuilder.withQuery(QueryBuilders.matchQuery("name", request.getKey())).withHighlightFields(titleField);

        //查詢,在查詢的基礎上給字段設置高亮紅色
        AggregatedPage<Goods> result = template.queryForPage(queryBuilder.build(), Goods.class,
                new SearchResultMapper() {
                    @Override
                    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                        List<Goods> list = new ArrayList<Goods>();
                        for (SearchHit searchHit : response.getHits()) {
                            if (response.getHits().getHits().length <= 0) {
                                return null;
                            }
                            Goods idea = new Goods();
                            HighlightField ideaTitle = searchHit.getHighlightFields().get("name");
                            if (ideaTitle != null) {
                                idea.setName(ideaTitle.fragments()[0].toString());
                            }
                            list.add(idea);
                        }
                        if (list.size() > 0) {
                            return new AggregatedPageImpl<T>((List<T>) list);
                        }
                        return null;
                    }
                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                        return null;
                    }
                }
        );

        //解析結果
        //分頁結果解析
        long total = result.getTotalElements();
        Long totalPages = result.getTotalPages();   
        List<Goods> goodsList = result.getContent();

        //封裝分頁數據
        return new PageResult(total, totalPages, goodsList);
    }

}
  1. Controller層(比較簡單,單純調用一下)
@RestController
public class SearchController {
    @Autowired
    private SearchService searchService;

    /**
     * 搜索功能
     * @param request
     * @return
     */
    @PostMapping("search")
    public ResponseEntity<PageResult<Goods>> search(@RequestBody SearchRequest request) {
        return ResponseEntity.ok(searchService.search(request));
    }
}
好了,代碼編寫完成,我們啓動我們的項目測試一下。

在這裏插入圖片描述

總結

​ 只是簡單的實現了一個springboot整合Elasticsearch的案例,我們還可以利用spring data提供的Repository接口做很多事情,比如對同一分類進行聚合爲桶等,天天學習,向大佬們靠近。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章