理想國SpringDataElasticSearch入門教程
阿新 • • 發佈:2020-12-24
技術標籤:Elasticsearch微服務Java
01.Spring Data 簡介
what:是什麼
- Spring Data是一個用於簡化持久層資料訪問的開源框架。
- 其主要目標是使得對資料的訪問變得方便快捷。
- Spring Data可以極大的簡化資料操作的寫法,可以在幾乎不用寫實現的情況下,實現對資料的訪問和操作。
- 包括CRUD外,還包括如分頁、排序等一些常用的功能,幾乎可以節省持久層程式碼80%以上的編碼工作量。
- Spring Data的官網:http://projects.spring.io/spring-data/
02.Spring Data ElasticSearch簡介
what:是什麼
- Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操作,將原始操作elasticSearch的客戶端API 進行封裝 。
- Spring Data為Elasticsearch專案提供整合搜尋引擎。
- Spring Data Elasticsearch POJO的關鍵功能區域為中心的模型與Elastichsearch互動文件和輕鬆地編寫一個儲存庫資料訪問層。
- 官方網站:http://projects.spring.io/spring-data-elasticsearch/
why:為什麼使用
- 用來操作ElasticSearch的框架,使得開發更加便捷
03.環境搭建
實現步驟:
- 建立SpringBoot的專案:版本為
<version>2.1.9.RELEASE</version>
- 勾選starter依賴座標
- 編寫持久層介面GoodDao,編寫pojo實體類
- 配置檔案,叢集配置,ElasticSearch服務地址http://127.0.0.1:9300
實現過程:
- 建立SpringBoot的專案!
- 勾選starter依賴座標,依賴如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lxgzhw</groupId>
<artifactId>springdata_es_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springdata_es_demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
編寫持久層介面GoodDao,編寫pojo實體類
package com.lxgzhw.dao;
public interface GoodDao {
}
pojo實體類,商品good:這裡的索引名稱不能是已存在的
package com.lxgzhw.pojo;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* 商品實體類
*
* @Document() 註解作用:定義一個索引庫,一個型別
* indexName屬性:指定索引庫的名稱
* type屬性:指定型別名稱
* shards屬性:指定分片數
* replicas屬性:指定複製副本數
*/
@Data
@Document(indexName = "lxgzhw1", type = "goods", shards = 5, replicas = 1)
public class Good {
private Long id;//商品的唯一標識
private String title;//標題
private String category;//分類
private String brand;//品牌
private Double price;//價格
private String images;//圖片地址
//getter,setter,toString
}
配置檔案:applacation.properties
- 叢集配置,ElasticSearch服務地址http://127.0.0.1:9301
- 這裡的叢集名稱和服務地址要與之前教程中配置的保持一致
# 配置叢集名稱
spring.data.elasticsearch.cluster-name=my-Elasticsearch
# 配置es的服務地址
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9301
04.建立和刪除索引
幾個用到的註解:
- @Document:宣告索引庫配置
- indexName:索引庫名稱
- type:型別名稱,預設是“docs”
- shards:分片數量,預設5
- replicas:副本數量,預設1
- @Id:宣告實體類的id
- @Field:宣告欄位屬性
- type:欄位的資料型別
- analyzer:指定分詞器型別
- index:是否建立索引 預設為true
- store:是否儲存 預設為false
實體類配置:
package com.lxgzhw.pojo;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* 商品實體類
*
* @Document() 註解作用:定義一個索引庫,一個型別
* indexName屬性:指定索引庫的名稱
* type屬性:指定型別名稱
* shards屬性:指定分片數
* replicas屬性:指定複製副本數
*/
@Data
@Document(indexName = "lxgzhw2", type = "goods", shards = 5, replicas = 1)
public class Good {
//必須有id,這裡的id是全域性唯一的標識,等同於es中的“_id”
@Id
private Long id;
/**
* type: 欄位資料型別
* analyzer: 分詞器型別
* index: 是否索引(預設值:true)
* store: 是否儲存(預設值:false)
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title;//標題
@Field(type = FieldType.Keyword)
private String category;//分類
@Field(type = FieldType.Keyword)
private String brand;//品牌
@Field(type = FieldType.Double)
private Double price;//價格
@Field(type = FieldType.Keyword, index = false)
private String images;//圖片地址
//getter ,setter ,toString
}
測試類:Demo01IndexOperationTests.java
package com.lxgzhw;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 建立索引
* 配置對映
* 刪除索引
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo01IndexOperationTests {
//模板設計模式
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Test
public void createIndexAndPutMapping() {
elasticsearchTemplate.createIndex(Good.class);//建立索引
elasticsearchTemplate.putMapping(Good.class);//配置對映
}
//刪除索引
@Test
public void deleteIndex() {
elasticsearchTemplate.deleteIndex(Good.class);
}
}
05.文件的常見增刪改查
修改GoodDao介面:繼承ElasticsearchRespository模板介面
package com.lxgzhw.dao;
import com.lxgzhw.pojo.Good;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface GoodDao extends ElasticsearchRepository<Good, Long> {
}
新增測試類:SpringdataEsGoodCRUDTests.java
package com.lxgzhw;
import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsGoodCRUDTests {
//注入Good業務層實現類
@Autowired
private GoodDao goodDao;
/**
* 新增
*/
@Test
public void save() {
Good good = new Good();
good.setId(1l);
good.setTitle("小米手機");
good.setCategory("手機");
good.setBrand("小米");
good.setPrice(19999.0);
good.setImages("http://image.leyou.com/12479122.jpg");
goodDao.save(good);
}
//修改
@Test
public void update() {
Good good = new Good();
good.setId(1l);
good.setTitle("小米手機");
good.setCategory("手機");
good.setBrand("小米");
good.setPrice(9999.0);
good.setImages("http://image.leyou.com/12479122.jpg");
goodDao.save(good);
}
//刪除
@Test
public void delete() {
Good good = new Good();
good.setId(1l);
goodDao.delete(good);
}
//根據id查詢
@Test
public void findById() {
Good good = goodDao.findById(1l).get();
System.out.println(good);
}
//查詢所有
@Test
public void findAll() {
Iterable<Good> goods = goodDao.findAll();
for (Good good : goods) {
System.out.println(good);
}
}
//批量新增
@Test
public void saveAll() {
List<Good> goodList = new ArrayList<>();
for (int i = 0; i < 500; i++) {
Good good = new Good();
good.setId((long) i);
good.setTitle("[" + i + "]小米手機");
good.setCategory("手機");
good.setBrand("小米");
good.setPrice(19999.0 + i);
good.setImages("http://image.leyou.com/12479122.jpg");
goodList.add(good);
}
goodDao.saveAll(goodList);
}
//分頁查詢
@Test
public void findByPageable() {
//設定排序(排序方式,正序還是倒序,排序的id)
Sort sort = new Sort(Sort.Direction.DESC, "id");
int currentPage = 2;//當前頁
int pageSize = 100;//每頁顯示多少條
//設定查詢分頁
PageRequest pageRequest = PageRequest.of(currentPage, pageSize, sort);
//分頁查詢
System.out.println("分頁資料:");
Page<Good> goodPage = goodDao.findAll(pageRequest);
for (Good good : goodPage.getContent()) {
System.out.println(good);
}
}
}
07.Search查詢
what:是什麼
- ElasticSearch的search方法中QueryBuilders,就是第一章中的查詢物件構建物件QueryBuilders。
- QueryBuilders具備的能力,search方法都具備。
- 所以,在這裡重複內容不贅述,僅舉例term查詢。
建立測試類:SpringdataEsSearchTests.java
package com.lxgzhw;
import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsSearchTests {
//注入Good業務層實現類
@Autowired
private GoodDao goodDao;
/**
* term查詢
* search(termQueryBuilder) 調用搜索方法,引數查詢構建器物件
*/
@Test
public void termQuery() {
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
Iterable<Good> goods = goodDao.search(termQueryBuilder);
for (Good g : goods) {
System.out.println(g);
}
}
/**
* term查詢加分頁
*/
@Test
public void termQueryByPage() {
int currentPage = 0;
int pageSize = 5;
//設定查詢分頁
PageRequest pageRequest = PageRequest.of(currentPage, pageSize);
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
Iterable<Good> goods = goodDao.search(termQueryBuilder, pageRequest);
for (Good g : goods) {
System.out.println(g);
}
}
}
08.自定義方法名稱查詢
what:是什麼
- GoodsRepository提供了非常強大的自定義查詢功能;只要遵循SpringData提供的語法,我們可以任意定義方法宣告
- 查詢語法:findBy+欄位名+Keyword+欄位名+…
Keyword | Sample | Elasticsearch Query String |
---|---|---|
And | findByNameAndPrice | {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or | findByNameOrPrice | {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is | findByName | {"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not | findByNameNot | {"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between | findByPriceBetween | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After | findByPriceAfter | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like | findByNameLike | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith | findByNameEndingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
In | findByNameIn(Collection<String>names) | {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn | findByNameNotIn(Collection<String>names) | {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
OrderBy | findByNameOrderByNameDesc | {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"name" : "?"}}} |
持久層介面:
package com.lxgzhw.dao;
import com.lxgzhw.pojo.Good;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
/**
* ElasticsearchRepository 持久層操作ElasticSearch的模板介面
*/
public interface GoodDao extends ElasticsearchRepository<Good, Long> {
/**
* 根據title和價格查詢,and的關係
*/
List<Good> findAllByTitleAndPrice(String title, Double price);
/**
* 根據商品價格範圍查詢
* 最低價格lowPrice
* 最高價格highPrice
*/
List<Good> findByPriceBetween(Double lowPrice, Double highPrice);
}
新增測試類:SpringdataEsCustomMethodQueryTests.java
package com.lxgzhw;
import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsCustomMethodQueryTests {
//注入Good業務層實現類
@Autowired
private GoodDao goodDao;
/**
* 根據標題及價格查詢
* 要求價格等於20023且標題的內容包含小米關鍵詞
*/
@Test
public void findAllByTitleAndPrice() {
String title = "小米";
Double price = 20023.0;
List<Good> goods = goodDao.findAllByTitleAndPrice(title, price);
for (Good g : goods) {
System.out.println(g);
}
}
/**
* 根據價格範圍查詢
* 要求商品價格再3000,到20000之間
*/
@Test
public void findPriceBetween() {
double lowPrice = 3000.0;//最低價
double highPrice = 20000.0;//最高價
List<Good> goods = goodDao.findByPriceBetween(lowPrice, highPrice);
for (Good g : goods) {
System.out.println(g);
}
}
}