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的整合實現搜索。
<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>
server:
port: 8888
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 192.168.43.238:9300 #ip地址填寫自己的
jackson:
default-property-inclusion: non_null #如果是空值則不返回
@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;
}
}
- 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> {
}
- 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);
}
}
- 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接口做很多事情,比如對同一分類進行聚合爲桶等,天天學習,向大佬們靠近。