选择 Elasticsearch-7.1.12
由于 选型的SpringCloud版本的优先级要高 所以在确定SpringCloud的版本之后
以此确定了 SpringBoot 版本、相关组件版本、Elasticsearch版本、spring-data-elasticsearch版本
由于生产环境要求稳定 所以并没有采用最新的版本
如果你有新版本的需要 可以根据如下链接进行查找
对于当前的学习环境 采用Docker的环境搭建 减少安装的问题 避免挫败学习兴趣
docker pull elasticsearch:7.12.1
docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms512m -Xms512m" -e "discovery.type=single-node" -p 9200:9200 elastics
earch:7.12.1
配置跨域
docker exec -it elasticsearch /bin/bash
vi config/elasticsearch.yml
修改当中内容为
cluster.name: "docker-cluster"
network.host: 0.0.0.0
http.cors.enabled: true
http.cors.allow-origin: "*"
根据提示退出保存
docker restart elasticsearch
浏览器访问
http://127.0.0.1:9200
安装 head
docker pull mobz/elasticsearch-head:5
docker run --name elasticsearch-head -d -p 9100:9100 mobz/elasticsearch-head:5
浏览器访问
http://127.0.0.1:9100
尝试向 Elasticsearch 中 写入、读取数据
打开 Postman
可以换不同的内容 多写入几条 方便后边的条件查询
http://127.0.0.1:9200/student/_doc/7
{
"id": 7,
"name": "wzk",
"age": "14"
}
http://127.0.0.1:9200/student/_search
{
"query": {
"match": {
"name": "wzk"
}
}
}
本章主要是 查询、各种检索方式、检索条件、排序、分页等等
http://127.0.0.1:9200/student/_search
{
"query": {
"match_all": {
}
}
}
分词后进行检索
http://127.0.0.1:9200/student/_search
{
"query": {
"match": {
"info": "oohohohoh"
}
}
}
搜索条件不做任何分词
http://127.0.0.1:9200/student/_search
{
"query": {
"match_phrase": {
"info": "is"
}
}
}
对数字类型的字段进行范围搜索
http://127.0.0.1:9200/student/_search
{
"query": {
"range": {
"id": {
"gt": 6,
"lte": 9
}
}
}
}
单词/词组搜索 搜搜条件不做任何分词解析 在搜索字段对应的倒排索引中精确匹配
http://127.0.0.1:9200/student/_search
{
"query": {
"terms": {
"info": ["is", "who"]
}
}
}
在搜索时可能会出现错误 Elasticsearch 会自动纠错 进行模糊匹配
http://127.0.0.1:9200/student/_search
{
"query": {
"match": {
"info": {
"query": "liyi",
"fuzziness": 1
}
}
}
}
多个条件结合 搜索符合的结果
http://127.0.0.1:9200/student/_search
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"info": "my"
}
},
{
"match_phrase": {
"info": "name"
}
}
],
"should": [
{
"match_phrase": {
"info": "name"
}
}
],
"must_not": [
{
"match_phrase": {
"info": "wzk"
}
}
]
}
}
}
对查询到的结果进行排序
由于elasticsearch对text类型字段数据会做分词处理
所以无论使用那个单词排序都是不合理的 所以默认不允许对text类型进行排序
如果要使用字符串结果排序
可以使用keyword类型的字段作为排序依据 因为keyword字段不做分词处理
http://127.0.0.1:9200/student/_search
{
"query": {
"match_all": {
}
},
"sort": [
{
"id": {
"order": "desc"
}
}
]
}
实际线上使用过程中 符合的结果可能很多
所以必须要对结果进行分页 提升效率
http://127.0.0.1:9200/student/_search
{
"query": {
"match_all": {
}
},
"from": 0,
"size": 2
}
http://127.0.0.1:9200/student/_search
{
"query": {
"match": {
"info": "is"
}
},
"highlight": {
"fields": {
"info": {
"fragment_size": 100,
"number_of_fragments": 5
}
}
}
}
搭建项目 在 SpringBoot 项目中使用 Elasticsearch
采用的方案是 SpringData 上手比较简单 (对我来说 但可能不是很自由 学习足够了)
假设你已经有SpringBoot的基础啦!
下面我就快刀斩乱麻 起一个项目 (随手parent为2.2.2.RELEASE)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<!-- spring-boot-web -->
<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>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
项目中新建 config 目录
新建配置类 (不要忘记 @Configuration)
@Configuration
public class ElasticSearchConfig extends AbstractElasticsearchConfiguration {
@Override
public RestHighLevelClient elasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration
.builder()
.connectedTo("127.0.0.1:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
结构和elasticsearch你存储的对象的字段可以对应
新建model文件夹
新建Student对象
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "student")
public class Student {
@Id
private Integer id;
@Field(type = FieldType.Text, store = true)
private String name;
@Field(type = FieldType.Text, store = true)
private String info;
@Field(type = FieldType.Text, store = true)
private String age;
@Field(type = FieldType.Text, store = true)
private String links;
}
ElasticsearchRepository是基础类 继承后 有很多现成的方法
新建 dao 文件夹
新建 StudentRepository 类
public interface StudentRepository extends ElasticsearchRepository<Student, Integer> {
}
这里为了省事 直接将逻辑放到了 Controller 上
将 StudentRepository 注入进来
SpringData 帮忙提供了很多现成的方法
@Autowired
private StudentRepository studentRepository;
@GetMapping("/addStudent")
public String addStudent() {
String name = UUID.randomUUID().toString();
name = name.replace("-", " ");
Student student = Student
.builder()
.name(name)
.links("this is a link to " + name)
.build();
studentRepository.save(student);
return "ok";
}
将 StudentRepository 注入进来
@Autowired
private StudentRepository studentRepository;
@GetMapping("/getStudent")
public List<Student> getStudent() {
Iterable<Student> dataList = studentRepository.findAll();
List<Student> resultList = new ArrayList<>();
for (Student student : dataList) {
resultList.add(student);
}
return resultList;
}
将 StudentRepository 注入进来
@Autowired
private StudentRepository studentRepository;
@GetMapping("/getStudentById")
public Student getStudentById() {
Optional<Student> stuData = studentRepository.findById(11);
return stuData.orElseGet(Student::new);
}
将 StudentRepository 注入进来
@Autowired
private StudentRepository studentRepository;
@GetMapping("/updStudent")
public String updStudent() {
String name = UUID.randomUUID().toString();
name = name.replace("-", " ");
Student student = Student
.builder()
.id(1)
.name(name)
.links("this is a link to " + name)
.build();
studentRepository.save(student);
return "ok";
}
将 StudentRepository 注入进来
@Autowired
private StudentRepository studentRepository;
@GetMapping("/delStudent")
public String delStudent() {
studentRepository.deleteById(1);
return "ok";
}
第5章 我们发现 虽然SpringData帮我们提供了很多方法(通过继承的方式)
但是不够自由 当查询时条件复杂就不可以使用了
所以官方也提供了对应的解决方案
// 根据名字查询
List<Student> findByName(String name);
// 根据名字模糊查询
List<Student> findByNameLike(String name);
Pageable pageable = PageRequest.of(0, 2); 即可实现分页查询
@Autowired
private StudentRepository studentRepository;
@GetMapping("/getPage")
public List<Student> getPage() {
Pageable pageable = PageRequest.of(0, 2);
Page<Student> page = studentRepository.findAll(pageable);
List<Student> dataList = page.getContent();
long number = page.getTotalElements();
int total = page.getTotalPages();
out.println("number: " + number);
out.println("total: "+ total);
return dataList;
}
6.2 中使用了 Pageable 分页
我们也可以利用 6.1中的方式进行分页
在 StudentRepository 中 加入方法
// 注意 Pageable page
// 这样逻辑大约变成了(方便理解 用SQL表达一下):
// select * from student where name=#{name} limit #{page.page, page.size}
Page<Student> findByNameLike(String name, Pageable page);
@Autowired
private StudentRepository studentRepository;
@GetMapping("/findByNamePage")
public List<Student> findByNamePage() {
Pageable pageable = PageRequest.of(0, 1);
// 传参 将 条件、分页 一起传入
Page<Student> data = studentRepository.findByNameLike("2", pageable);
System.out.println(data.getTotalElements());
System.out.println(data.getTotalPages());
return data.getContent();
}
查询时 进行排序
Sort sort = Sort.by(Sort.Direction.DESC, “id”);
@Autowired
private StudentRepository studentRepository;
@GetMapping("/findByNameOrder")
public List<Student> findByNameOrder() {
// 排序顺序、排序字段
Sort sort = Sort.by(Sort.Direction.DESC, "id");
Iterable<Student> dataList = studentRepository.findAll(sort);
List<Student> resultList = new ArrayList<>();
for (Student student : dataList) {
resultList.add(student);
}
return resultList;
}
Pageable 中加入了 Sort 所以可以分页、排序
@Autowired
private StudentRepository studentRepository;
@GetMapping("/findByNamePageOrder")
public List<Student> findByNamePageOrder() {
Sort sort = Sort.by(Sort.Direction.ASC, "id");
// 传参 start、limit、sort规则
// 即可实现 分页 + 排序
Pageable pageable = PageRequest.of(0,2, sort);
Page<Student> page = studentRepository.findAll(pageable);
return page.getContent();
}