Elasticsearch整合SpingData
一.概念(倒排索引)
查询疑问:使用Elasticsearch搜索时会发现,有时候搜出来的数据和自己想要的不一样。
因为Elasticsearch引入的分词器,会将字符拆分成不同的词组,而Elasticsearch
查询时引入了倒排索引的一个概念。拆分的词组与之匹配所以会查出一些与词组
匹配的数据。
正排索引:
当查询一条数据时,是依次一条条查按顺序查过去时是正排索引。
倒排索引:
什么是倒排索引,以两句话作为例子:
句1:我想买华为手机 句2:我想买小米手机
第1句话会被分词器拆分为: 1我想买 2华为 3手机
第2句话会被分词器拆分为: 1我想买 2小米 3手机
相同的词语会被的id会被放在一起,当我们查询 “我想买”时
句1,句2话都会被查询出来。
而查询条件为”小米“时 句2会被精确查询出来。
总结为一句话:
不同的话被拆分成不同点词段,当查询到对应的词段,词段会对应与i给id集合,之后将着一些数据查寻出来。
二.准备环境
1.官网地址www.elastic.co/cn/
2.官方文档www.elastic.co/guide/index…
3.Elasticsearch7.8.0的下载地址www.elastic.co/cn/download…
4.Elasticsearch7.8.0的教学文档(136条消息) Elasticsearch学习笔记_巨輪的博客-CSDN博客
三.Elasticsearch
解压后,进入 bin 文件目录,点击 elasticsearch.bat 文件启动 ES 服务 。
注意: 9300 端口为 Elasticsearch 集群间组件的通信端口, 9200 端口为浏览器访问的 http协议 RESTful 端口。
打开浏览器,输入地址: http://localhost:9200,测试返回结果,返回结果如下:
{
"name" : "DESKTOP-LNJQ0VF",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "nCZqBhfdT1-pw8Yas4QU9w",
"version" : {
"number" : "7.8.0",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
"build_date" : "2020-06-14T19:35:50.234439Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
二.使用springData整合Elasticsearch
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--springdata整合elasticsearch的依赖 -->
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
2.yml
spring:
application:
name: es
elasticsearch:
host: 127.0.0.1 #elasticsearch服务地址 (自定义)
port: 9200 #elasticsearch服务端口(自定义)
server:
port: 9000
3.创建配置类
ElasticsearchRestTemplate是spring-data-elasticsearch项目中的一个类,和其他spring项目中的 template类似。 在新版的spring-data-elasticsearch 中,ElasticsearchRestTemplate 代替了原来的ElasticsearchTemplate。 原因是ElasticsearchTemplate基于TransportClient,TransportClient即将在8.x 以后的版本中移除。所以,我们推荐使用ElasticsearchRestTemplate。 ElasticsearchRestTemplate基于RestHighLevelClient客户端的。需要自定义配置类,继承AbstractElasticsearchConfiguration,并实现elasticsearchClient()抽象方法,创建RestHighLevelClient对象。
package com.example.springdataelasticsearch.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
@Value("${elasticsearch.host}")
private String host ;
@Value("${elasticsearch.port}")
private Integer port ;
//重写父类方法
@Override
public RestHighLevelClient elasticsearchClient() {
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
RestHighLevelClient restHighLevelClient = new
RestHighLevelClient(builder);
return restHighLevelClient;
}
}
4.创建Elasticsearch实体类
package com.example.springdataelasticsearch.es;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
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;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document(indexName = "shopping",shards = 6,replicas = 1) //shopping 如果索引不存在自动创建
public class ProductEntity {
@Id
private Long id;//商品唯一标识
/**
* type : 字段数据类型
* analyzer : 分词器类型
* index : 是否索引(默认:true)
* Keyword : 短语,不进行分词
* 1、ik_max_word
* 会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂 * 等词语。
* 2、ik_smart
* 会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title;//商品名称
@Field(type = FieldType.Keyword)
private String category;//分类名称
@Field(type = FieldType.Double)
private Double price;//商品价格
@Field(type = FieldType.Keyword, index = false)
private String images;//图片地址
}
5.创建Elasticsearch DAO数据访问对象
package com.example.springdataelasticsearch.dao;
import com.example.springdataelasticsearch.es.ProductEntity;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ProductDao extends ElasticsearchRepository<ProductEntity, Long> {
}
6.测试集成框架SpirngData
package com.example.springdataelasticsearch;
import com.example.springdataelasticsearch.dao.ProductDao;
import com.example.springdataelasticsearch.es.ProductEntity;
import org.junit.jupiter.api.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.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringDataElasticsearchApplicationTests {
@Autowired
private ProductDao productDao;
// @Autowired
// private ElasticsearchRestTemplate elasticsearchRestTemplate;
// @Test
// void createIndex() {
// //创建索引,系统初始化会自动创建索引
// System.out.println();
// }
//
// @Test
// public void deleteIndex(){
// //创建索引,系统初始化会自动创建索引
// boolean flg = elasticsearchRestTemplate.deleteIndex(ProductEntity.class);
// System.out.println("删除索引 = " + flg);
// }
@Test
public void save(){
ProductEntity product = new ProductEntity();
product.setId(2L);
product.setTitle("华为手机");
product.setCategory("手机");
product.setPrice(2999.0);
product.setImages("http://www.atguigu/hw.jpg");
productDao.save(product);
}
//POSTMAN, GET http://localhost:9200/product/_doc/2
//修改
@Test
public void update(){
ProductEntity product = new ProductEntity();
product.setId(2L);
product.setTitle("小米 2 手机");
product.setCategory("手机");
product.setPrice(9999.0);
product.setImages("http://www.atguigu/xm.jpg");
productDao.save(product);
}
//POSTMAN, GET http://localhost:9200/product/_doc/2
//根据 id 查询
@Test
public void findById(){
ProductEntity product = productDao.findById(2L).get();
System.out.println(product);
}
@Test
public void findAll(){
Iterable<ProductEntity> products = productDao.findAll();
for (ProductEntity product : products) {
System.out.println(product);
}
}
//删除
@Test
public void delete(){
ProductEntity product = new ProductEntity();
product.setId(2L);
productDao.delete(product);
}
//POSTMAN, GET http://localhost:9200/product/_doc/2
//批量新增
@Test
public void saveAll(){
List<ProductEntity> productList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
ProductEntity product = new ProductEntity();
product.setId(Long.valueOf(i));
product.setTitle("["+i+"]小米手机");
product.setCategory("手机");
product.setPrice(1999.0 + i);
product.setImages("http://www.atguigu/xm.jpg");
productList.add(product);
}
productDao.saveAll(productList);
}
//分页查询
@Test
public void findByPageable(){
//设置排序(排序方式,正序还是倒序,排序的 id)
Sort sort = Sort.by(Sort.Direction.DESC,"id");
int currentPage=0;//当前页,第一页从 0 开始, 1 表示第二页
int pageSize = 5;//每页显示多少条
//设置查询分页
PageRequest pageRequest = PageRequest.of(currentPage, pageSize,sort);
//分页查询
Page<ProductEntity> productPage = productDao.findAll(pageRequest);
for (ProductEntity ProductEntity : productPage.getContent()) {
System.out.println(ProductEntity);
}
}
}