蘇玲老師Git課程學習筆記
阿新 • • 發佈:2020-12-22
前言
本文介紹SpringBoot2.3整合Elasticsearch7.x完整版流程
廢話不多說,直接開始
準備
1、首先確保安裝docker和docker-compose,如還未安裝docker以及docker-compose,請閱讀 Centos7.X安裝docker及docker-compose 來安裝,若已經安裝,請繼續檢視以下教程
2、Springboot版本:2.3.3.RELEASE;Elasticsearch版本:7.7.0 ;Kibana:7.7.0;jdk:1.8
安裝Elasticsearch及Kibana
本文介紹以docker-compose方式來安裝
mkdir -R /wilton/elasticsearch cd /wilton/elasticsearch
編輯指令碼:vim docker-compose.yml
version: '3' services: elasticsearch: image: elasticsearch:7.7.0 container_name: elasticsearch environment: - "cluster.name=elastic" #設定叢集名稱為elastic - "discovery.type=single-node" #以單一節點模式啟動 - "ES_JAVA_OPTS=-Xms2048m -Xmx4096m" #設定使用jvm記憶體大小 volumes: - /wilton/elasticsearch/data/plugins:/usr/share/elasticsearch/plugins #外掛檔案掛載 - /wilton/elasticsearch/data/data:/usr/share/elasticsearch/data #資料檔案掛載 - /wilton/elasticsearch/data/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml #配置檔案掛載 ports: - 9200:9200 - 9300:9300 kibana: image: kibana:7.7.0 container_name: kibana links: - elasticsearch:es #配置elasticsearch域名為es depends_on: - elasticsearch #kibana在elasticsearch啟動之後再啟動 environment: - "elasticsearch.hosts=http://127.0.0.1:9200" #設定訪問elasticsearch的地址 volumes: - /wilton/kibana/data/config:/usr/share/kibana/config #配置檔案掛載 ports: - 5601:5601
elasticsearch.yml配置檔案
cluster.name: "docker-master"
network.host: 0.0.0.0
kibana.yml配置檔案
server.name: kibana
server.host: "0"
elasticsearch.hosts: [ "http://127.0.0.1:9200" ]
i18n.locale: "zh-CN"
啟動
docker-compose up -d
訪問 kibana:http://localhost:5601/
SpringBoot整合 Spring Data Elasticsearch
Spring Data Elasticsearch是Spring提供的一種以Spring Data風格來操作資料儲存的方式,它可以避免編寫大量的樣板程式碼。
SpringBoot版本:2.3
- 新增 pom 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
-
常用註解:
@Document :標示對映到Elasticsearch文件上的領域物件
//標示對映到Elasticsearch文件上的領域物件 public @interface Document { //索引庫名次,mysql中資料庫的概念 String indexName(); //文件型別,mysql中表的概念 String type() default ""; //預設分片數 short shards() default 5; //預設副本數量 short replicas() default 1; }
@Id :表示是文件的id,文件可以認為是mysql中表行的概念
//表示是文件的id,文件可以認為是mysql中表行的概念 public @interface Id { }
@Filed :文件中欄位的型別、是否建立倒排索引、是否進行儲存
public @interface Field { //文件中欄位的型別 FieldType type() default FieldType.Auto; //是否建立倒排索引 boolean index() default true; //是否進行儲存 boolean store() default false; //分詞器名次 String analyzer() default ""; }
//為文件自動指定元資料型別 public enum FieldType { Text,//會進行分詞並建了索引的字元型別 Integer, Long, Date, Float, Double, Boolean, Object, Auto,//自動判斷欄位型別 Nested,//巢狀物件型別 Ip, Attachment, Keyword//不會進行分詞建立索引的型別 }
修改application.yml配置檔案
修改application.yml檔案,在spring節點下新增Elasticsearch相關配置。
spring:
data:
elasticsearch:
repositories:
enabled: true
cluster-nodes: 127.0.0.1:9300 # es的連線地址及埠號
cluster-name: elastic # es叢集的名稱
實體物件
User.java
package cn.wilton.framework.es.document;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.time.LocalDate;
/**
* @Description es人員資訊
* @Author: Ranger
* @Date: 2020/12/21 17:04
* @Email: [email protected]
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Document(indexName = "user",type = "docs",shards = 1,replicas = 0)
public class User {
private static final long serialVersionUID = -1L;
@Id
private Long id;
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
private String name;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String address;
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
private String mobile;
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
private String email;
@Field(type = FieldType.Date, format = DateFormat.date)
private LocalDate birthday;
@Field(type = FieldType.Keyword)
private String idCard;
@Field
private Company company;
}
Company.java
package cn.wilton.framework.es.document;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* @Description
* @Author: Ranger
* @Date: 2020/12/22 10:12
* @Email: [email protected]
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Company {
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
private String name;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String address;
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
private String mobile;
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
private String email;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String nature;
@Field(type = FieldType.Text)
private String website;
}
官方介面:
ElasticsearchRepository<T, ID>
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.data.elasticsearch.repository;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.lang.Nullable;
@NoRepositoryBean
public interface ElasticsearchRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
/** @deprecated */
@Deprecated
default <S extends T> S index(S entity) {
return this.save(entity);
}
/** @deprecated */
@Deprecated
<S extends T> S indexWithoutRefresh(S var1);
/** @deprecated */
Iterable<T> search(QueryBuilder var1);
/** @deprecated */
Page<T> search(QueryBuilder var1, Pageable var2);
/** @deprecated */
Page<T> search(Query var1);
Page<T> searchSimilar(T var1, @Nullable String[] var2, Pageable var3);
/** @deprecated */
@Deprecated
void refresh();
}
PagingAndSortingRepository<T, ID>
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.data.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort var1);
Page<T> findAll(Pageable var1);
}
CrudRepository<T, ID>
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.data.repository;
import java.util.Optional;
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S var1);
<S extends T> Iterable<S> saveAll(Iterable<S> var1);
Optional<T> findById(ID var1);
boolean existsById(ID var1);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> var1);
long count();
void deleteById(ID var1);
void delete(T var1);
void deleteAll(Iterable<? extends T> var1);
void deleteAll();
}
自定義Repository
package cn.wilton.framework.es.repository;
import cn.wilton.framework.es.document.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.util.Streamable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* @Description
* @Author: Ranger
* @Date: 2020/12/22 10:21
* @Email: [email protected]
*/
@Repository
public interface OrderRepository extends ElasticsearchRepository<User,Long> {
/**
* 根據名字查詢數量
*
* @param name
* @return
*/
long countByName(String name);
/**
* 根據地址查詢
*
* @param address
* @return
*/
long countByAddress(String address);
/**
* 根據名字刪除,並返回刪除數量
*
* @param name
* @return
*/
long deleteByName(String name);
/**
* 根據名字刪除並返回刪除物件
*
* @param name
* @return
*/
List<User> removeByName(String name);
/**
* 根據名字查詢
*
* @param name
* @return
*/
List<User> findByName(String name);
/**
* 根據eamil和名字查詢
*
* @param email
* @param name
* @return
*/
List<User> findByEmailAndName(String email, String name);
/**
* 根據email或者手機號查詢
*
* @param email
* @param mobile
* @return
*/
List<User> findDistinctByEmailOrMobile(String email, String mobile);
/**
* 根據名字分頁查詢
*
* @param name
* @param page
* @return
*/
Page<User> findByName(String name, Pageable page);
/**
* 根據名字按照id倒序排列查詢
*
* @param name
* @param page
* @return
*/
Page<User> findByNameOrderByIdDesc(String name, Pageable page);
/**
* 根據company物件下的name屬性查詢
*
* @param companyName
* @param page
* @return
*/
Page<User> findByCompanyName(String companyName, Pageable page);
/**
* 根據company物件下的name或者根據company物件下的nature屬性查詢
*
* @param companyName
* @param ompanyNature
* @return
*/
List<User> findByCompanyNameOrCompanyNature(String companyName, String ompanyNature);
/**
* 根據id範圍查詢
*
* @param start
* @param end
* @return
*/
List<User> findByIdBetween(Long start, Long end);
/**
* id小於引數查詢
*
* @param id
* @return
*/
List<User> findByIdLessThan(Long id);
/**
* 名字模糊查詢並且根據id範圍查詢
*
* @param name
* @param from
* @param to
* @return
*/
List<User> findByNameLikeAndIdBetween(String name, Long from, Long to);
/**
* 忽略email大小寫查詢
*
* @param email
* @return
*/
List<User> findByEmailIgnoreCaseLike(String email);
/**
* 查詢前10
*
* @param name
* @param sort
* @return
*/
List<User> findFirst10ByName(String name, Sort sort);
/**
* 查詢前3
*
* @param name
* @param pageable
* @return
*/
Slice<User> findTop3ByName(String name, Pageable pageable);
/**
* 根據名字查詢前10分頁
*
* @param name
* @param pageable
* @return
*/
Page<User> queryFirst10ByName(String name, Pageable pageable);
/**
* 小於引數id查詢
*
* @param id
* @return
*/
Streamable<User> queryByIdLessThan(Long id);
/**
* 大於id引數查詢
*
* @param id
* @return
*/
Streamable<User> queryByIdGreaterThan(Long id);
/**
* 根據名字非同步查詢
*
* @param name
* @return
*/
@Async
CompletableFuture<User> findOneByName(String name);
@Query("{\"range\":{\"id\":{\"from\":\"?0\",\"to\":\"?1\"}}}")
List<User> queryByIdSql(Long start, Long end);
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
List<User> queryByNameSql(String name);
}
測試介面:
package cn.wilton.framework.es;
import cn.wilton.framework.WiltonElasticsearchApplication;
import cn.wilton.framework.es.document.Company;
import cn.wilton.framework.es.document.User;
import cn.wilton.framework.es.repository.OrderRepository;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
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.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.util.Streamable;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
* @Description
* @Author: Ranger
* @Date: 2020/12/22 11:09
* @Email: [email protected]
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = WiltonElasticsearchApplication.class)
public class EsTest {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ElasticsearchRestTemplate esRestTemplate;
@Test
public void saveTest() {
Company c = new Company("百度線上網路技術(北京)有限公司", "北京市海淀區中關村街道", "18510367878", "[email protected]", "網際網路",
"https://www.baidu.com");
User p = new User(1L, "李四", "北京市海淀區中關村街道", "165187413544", "[email protected]", LocalDate.of(1999, 2, 12),
"321302199902121478", c);
User save = orderRepository.save(p);
log.info("儲存後的結果 {} ", JSONObject.toJSONString(save,true));
}
@Test
public void deleteByIdTest() {
long id = 0L;
orderRepository.deleteById(id);
log.info("刪除資料id {}", id);
}
@Test
public void findAllSortTest() {
// 排序的列
Sort sort = Sort.by("birthday");
// 升序
log.info("升序 {}", JSONObject.toJSONString(orderRepository.findAll(sort),true));
// sort.descending() 倒序
log.info("倒序 {}", JSONObject.toJSONString(orderRepository.findAll(sort.descending()),true));
}
@Test
public void countByNameTest() {
String name = "良";
long count = orderRepository.countByName(name);
log.info("姓名:{},數量: {}", name, count);
}
@Test
public void countByAddressTest() {
String address = "深圳";
long count = orderRepository.countByAddress(address);
log.info("地址:{},數量: {}", address, count);
}
@Test
public void deleteByNameTest() {
String name = "張四";
long count = orderRepository.deleteByName(name);
log.info("刪除姓名:{},刪除數量: {}", name, count);
}
@Test
public void findByNameTest() {
String name = "李四";
List<User> list = orderRepository.findByName(name);
log.info("姓名:{},結果: {}", name, JSONObject.toJSONString(list, true));
}
@Test
public void findByEmailAndNameTest() {
String name = "阿良";
String email = "[email protected]";
List<User> list = orderRepository.findByEmailAndName(email, name);
log.info("email:{},name: {},結果: {}", email, name, JSONObject.toJSONString(list, true));
}
@Test
public void findDistinctByEmailOrMobile() {
String email = "[email protected]";
String mobile = "16518741234";
List<User> list = orderRepository.findDistinctByEmailOrMobile(email, mobile);
log.info("email:{},mobile: {},結果: {}", email, mobile, JSONObject.toJSONString(list, true));
}
@Test
public void findByNamePageTest() {
// 分頁查詢
String name = "李四";
// 從0開始
int page = 0;
// 必須大於0
int size = 2;
// 排序可以這樣
// 方式1
// Sort sort = Sort.by("id");
// PageRequest.of(page, size, sort);
// 方式2
Sort.TypedSort<User> typedSort = Sort.sort(User.class);
Sort sort = typedSort.by(User::getId).ascending().and(typedSort.by(User::getBirthday).descending());
Pageable pageable = PageRequest.of(page, size, sort);
Page<User> result = orderRepository.findByName(name, pageable);
log.info("name: {}, 分頁結果: {}", name, JSONObject.toJSONString(result, true));
}
@Test
public void findByNameNoPageTest() {
// 不分頁
String name = "李四";
Pageable unpaged = Pageable.unpaged();
Page<User> result = orderRepository.findByName(name, unpaged);
log.info("name: {}, 分頁結果: {}", name, JSONObject.toJSONString(result, true));
}
@Test
public void findByNameOrderByIdDescTest() {
String name = "李四";
// 從0開始
int page = 0;
// 必須大於0
int size = 2;
Pageable pageable = PageRequest.of(page, size);
Page<User> result = orderRepository.findByNameOrderByIdDesc(name, pageable);
log.info("name: {}, 分頁結果: {}", name, JSONObject.toJSONString(result, true));
}
@Test
public void findByCompanyTest() {
// 從0開始
int page = 0;
// 必須大於0
int size = 2;
Pageable pageable = PageRequest.of(page, size);
String companyName = "華為";
Page<User> result = orderRepository.findByCompanyName(companyName, pageable);
log.info("分頁結果: {}", JSONObject.toJSONString(result, true));
}
@Test
public void findByCompanyNameOrCompanyNatureTest() {
String companyName = "度";
String ompanyNature = "硬體";
List<User> list = orderRepository.findByCompanyNameOrCompanyNature(companyName, ompanyNature);
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void findByIdBetweenTest() {
long start = 1L;
long end = 3L;
List<User> list = orderRepository.findByIdBetween(start, end);
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void findByIdLessThanTest() {
long id = 3L;
List<User> list = orderRepository.findByIdLessThan(id);
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void findByIdBetweenAndNameTest() {
long start = 1L;
long end = 5L;
String name = "李";
List<User> list = orderRepository.findByNameLikeAndIdBetween(name, start, end);
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void findByEmailIgnoreCaseTest() {
String email = "Huawei";
List<User> list = orderRepository.findByEmailIgnoreCaseLike(email);
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void streamableTest() {
// 將結果合併
Streamable<User> streamable = orderRepository.queryByIdGreaterThan(5L)
.and(orderRepository.queryByIdLessThan(2L));
List<User> list = streamable.toList();
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void findOneByNameTest() throws InterruptedException, ExecutionException {
String name = "李四";
CompletableFuture<User> future = orderRepository.findOneByName(name);
User User = future.get();
log.info("結果: {}", JSONObject.toJSONString(User, true));
}
@Test
public void queryBySqlTest() {
List<User> list = orderRepository.queryByIdSql(1L, 3L);
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
@Test
public void queryByNameSqlTest() {
List<User> list = orderRepository.queryByNameSql("李四");
log.info("結果: {}", JSONObject.toJSONString(list, true));
}
}
Spring Data Elasticsearch 介面表示式說明
關鍵字 | 示例 | 查詢資訊 |
---|---|---|
And | findByNameAndPrice | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }} |
Or | findByNameOrPrice | { “query” : { “bool” : { “should” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }} |
Is | findByName | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }} |
Not | findByNameNot | { “query” : { “bool” : { “must_not” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }} |
Between | findByPriceBetween | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }} |
LessThan | findByPriceLessThan | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : false } } } ] } }} |
LessThanEqual | findByPriceLessThanEqual | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }} |
GreaterThan | findByPriceGreaterThan | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : false, “include_upper” : true } } } ] } }} |
GreaterThanEqual | findByPriceGreaterThan | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }} |
Before | findByPriceBefore | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }} |
After | findByPriceAfter | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }} |
Like | findByNameLike | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
StartingWith | findByNameStartingWith | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
EndingWith | findByNameEndingWith | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “*?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
Contains/Containing | findByNameContaining | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
In | findByNameIn(Collectionnames) | { “query” : { “bool” : { “must” : [ {“bool” : {“must” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }} |
NotIn | findByNameNotIn(Collectionnames) | { “query” : { “bool” : { “must” : [ {“bool” : {“must_not” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }} |
Near | findByStoreNear | Not Supported Yet ! |
TRUE | findByAvailableTrue | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }} |
FALSE | findByAvailableFalse | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “false”, “fields” : [ “available” ] } } ] } }} |
OrderBy | findByAvailableTrueOrderByNameDesc | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }, “sort”:[{“name”:{“order”:“desc”}}] } |