文章目录
一、SpringDataES实现ES操作
1、项目搭建
-
在myes空项目下,创建一个新模块,创建springboot项目myes2
-
选择2.7.9版本,并且选择两个依赖
-
创建application.yml文件,配置ES
spring: elasticsearch: uris: 192.168.126.24:9200
-
创建包com.zzx.myes2.document,在包下创建实体类Product
package com.zzx.myes2.document; import lombok.AllArgsConstructor; 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 = "product",createIndex = true) @Data @AllArgsConstructor public class Product { @Id @Field(type = FieldType.Integer,store = true,index = true) private Integer id; @Field(type = FieldType.Text,store = true,index = true,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word") private String productName; @Field(type = FieldType.Text,store = true,index = true,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word") private String productDesc; }
1)@Document:标记在类上,标记实体类为文档对象,一般有如下属性:
indexName:对应索引的名称
createIndex:是否自动创建索引
2)@Id:标记在成员变量上,标记一个字段为主键,该字段的值会同步到ES该文档的id值。
3)@Field:标记在成员变量上,标记为文档中的域,一般有如下属性:
type:域的类型
index:是否创建索引,默认是 true。即可以通过该域的关键词进行搜索
store:是否单独存储,默认是 false。即相当于将该列进行单独存储
analyzer:分词器
searchAnalyzer:搜索时的分词器。一般与analyzer属性保持一致即可。
2、使用Repository接口方法
-
创建包com.zzx.myes2.repository,在包下创建ProductRepository接口
package com.zzx.myes2.repository; import com.zzx.myes2.document.Product; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; public interface ProductRepository extends ElasticsearchRepository<Product,Integer> { }
-
在test根目录下,创建包com.zzx.myes2.repositorytest,在包下创建ProductRepositoryTest测试类
package com.zzx.myes2.repositorytest; import com.zzx.myes2.document.Product; import com.zzx.myes2.repository.ProductRepository; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Optional; @SpringBootTest public class ProductRepositoryTest { @Autowired private ProductRepository repository; //新建文档 @Test public void addDocument(){ Product product = new Product(1, "小米手机", "暖手宝"); repository.save(product); } //更新文档 @Test public void updateDocument(){ Product product = new Product(1, "小米手机2", "暖手宝2"); repository.save(product); } //查询所有文档 @Test public void findAllDocument(){ Iterable<Product> all = repository.findAll(); for (Product product : all) { System.out.println(product); } } //根据id查询文档 @Test public void findDocumentById(){ Optional<Product> product = repository.findById(1); System.out.println(product.get()); } //根据id删除文档 @Test public void deleteDocument(){ repository.deleteById(1); } }
此时操作时可能会报错,可能是springboot版本跟Elasticsearch版本不一致导致的响应正文无法解析,但是这个操作是正确的,能存到ES服务器中。
3、使用DSL查询文档
使用@Query注解实现DSL查询文档
-
往addDocument方法中加入添加文档的语句
repository.save(new Product(2, "小米手机3", "暖手宝3")); repository.save(new Product(3, "小米手机4", "暖手宝4")); repository.save(new Product(4, "小米手机5", "暖手宝5")); repository.save(new Product(5, "小米手机6", "暖手宝6"));
不过因为无法解析响应正文,每次只能添加一条。
-
在ProductRepository接口下添加两个方法
@Query("{"+ " \"match\" :{"+ " \"productDesc\": \"?0\""+ "}"+ "}") List<Product> findByProductDescMatch(String keyword); @Query("{\n" + " \"match\": {\n" + " \"productDesc\": {\n" + " \"query\": \"?0\",\n" + " \"fuzziness\": 1\n" + " }\n" + " }\n" + " }") List<Product> findByProductDescFuzzy(String keyword);
-
在com.zzx.myes2.repositorytest包下的ProductRepositoryTest类中添加两个方法
@Test public void testFindByProductDescMatch(){ List<Product> list = repository.findByProductDescMatch("我想能暖手的手机"); list.forEach(System.out::println); } @Test public void testFindByProductDescFuzzy(){ List<Product> list = repository.findByProductDescFuzzy("冷手宝"); list.forEach(System.out::println); }
两个方法都根据ProductDesc搜索,但是第一个方法是普通搜索,第二个则是模糊查询,可以容错。
4、按照规则来命名方法进行查询
按照规则来命名方法,方法名以findBy开头
-
在com.zzx.myes2.repository包下的ProductRepository接口中添加方法
List<Product> findByProductName(String productName); List<Product> findByProductNameOrProductDesc(String productName,String productDesc); List<Product> findByIdBetween(Integer startId,Integer endId);
-
在Test根目录下的com.zzx.myes2.repositorytest包下的ProductRepositoryTest类中添加方法进行测试
@Test public void testFindByProductName(){ List<Product> list = repository.findByProductName("小米手机3"); list.forEach(System.out::println); } @Test public void testFindByProductNameOrProductDesc(){ List<Product> list = repository.findByProductNameOrProductDesc("小米手机3","暖手宝x"); list.forEach(System.out::println); } @Test public void testFindByIdBetween(){ List<Product> list = repository.findByIdBetween(1,2); list.forEach(System.out::println); }
在继承ElasticsearchRepository接口的接口下,编写方法,以findBy开头,并且以一定的规则命名即可通过该方法进行查询。此时不用编写DSL语句
5、分页查询
-
在com.zzx.myes2.repository包下的ProductRepository接口中添加方法
Page<Product> findByProductDesc(String productDesc, Pageable pageable);
-
在Test根目录下的com.zzx.myes2.repositorytest包下的ProductRepositoryTest类中添加方法进行测试
//使用自定义的分页查询 @Test public void testFindPage2(){ //根据id倒序排序 Sort sort = Sort.by(Sort.Direction.DESC, "id"); //显示第一页,每页显示一条 Pageable pageable = PageRequest.of(0, 1,sort); Page<Product> page = repository.findByProductDesc("暖手",pageable); System.out.println("总页数:"+page.getTotalPages()); System.out.println("总条数:"+page.getTotalElements()); System.out.println("数据:"+page.getContent()); } //此时使用继承的固定方法实现分页查询 @Test public void testFindPage(){ //显示第一页,每页显示一条 Pageable pageable = PageRequest.of(0, 1); Page<Product> page = repository.findAll(pageable); System.out.println("总页数:"+page.getTotalPages()); System.out.println("总条数:"+page.getTotalElements()); System.out.println("数据:"+page.getContent()); }
第二个方法直接调用即可。
6、结果排序
- 在Test根目录下的com.zzx.myes2.repositorytest包下的ProductRepositoryTest类中添加方法进行测试
@Test public void testFindSort(){ //根据id倒序排序 Sort sort = Sort.by(Sort.Direction.DESC, "id"); Iterable<Product> products = repository.findAll(sort); for (Product product : products) { System.out.println(product); } }
二、SpringDataES的template工具类实现ES操作
1、操作索引
-
创建包com.zzx.myes2.templatetest,在包下创建TemplateTest类
package com.zzx.myes2.templatetest; import com.zzx.myes2.document.Product; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.IndexOperations; @SpringBootTest public class TemplateTest { @Autowired private ElasticsearchRestTemplate template; //新增索引 @Test public void addIndex(){ //获得索引操作对象 IndexOperations indexOperations = template.indexOps(Product.class); //创建索引 修改Product实体类,自动创建设置为false并且修改索引名字 indexOperations.create(); } //删除索引 @Test public void deleteIndex(){ //获得索引操作对象 IndexOperations indexOperations = template.indexOps(Product.class); //删除索引 indexOperations.delete(); } }
即通过注入SpringDataES的ElasticsearchRestTemplate工具类,调用该类的方法操作ES。
2、增删改查文档
-
在com.zzx.myes2.templatetest包下的TemplateTest类添加增加文档方法
//新增/修改文档 @Test public void addDocument(){ //获得索引操作对象 Product hzw = new Product(7, "hzw", "海贼,王路飞"); template.save(hzw); } //删除文档 @Test public void delDocument(){ template.delete("7",Product.class); }
此时添加和删除操作会返回无法解析响应正文的错误,但是文档可以操作成功。
-
在com.zzx.myes2.templatetest包下的TemplateTest类添加查询文档方法
//查询文档 @Test public void searchDocument(){ //1.确定查询方式 MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); //2.构建查询条件 NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQueryBuilder).build(); //3.查询 SearchHits<Product> search = template.search(query, Product.class); //4.处理查询结果 for (SearchHit<Product> productSearchHit : search) { System.out.println(productSearchHit); } }
3、复杂查询
-
在com.zzx.myes2.templatetest包下的TemplateTest类添加复杂查询文档方法
//复杂查询文档 @Test public void searchDocument2(){ String productName = "hzw"; String productDesc="暖手宝3"; //1.确定查询方式 多条件查询 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); //如果没有传入参数 查询所有 if((productName==null||productName.length()==0)&&(productName==null||productName.length()==0)) { MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); boolQueryBuilder.must(matchAllQueryBuilder); }else{ if(productName != null && productName.length()>0){ MatchQueryBuilder productName1 = QueryBuilders.matchQuery("productName", productName); boolQueryBuilder.should(productName1); } if(productDesc!= null && productDesc.length()>0){ MatchQueryBuilder productDesc1 = QueryBuilders.matchQuery("productDesc", productDesc); boolQueryBuilder.should(productDesc1); } } //2.构建查询条件 NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).build(); //3.查询 SearchHits<Product> search = template.search(query, Product.class); //4.处理查询结果 for (SearchHit<Product> productSearchHit : search) { System.out.println(productSearchHit); } }
复杂文档查询和文档查询的步骤除了前面查询方式不同之外基本一致,创建多条件查询构造器BoolQueryBuilder,通过往该构造器中添加查询条件即可,添加的方式有must、should、mustNot三种。
4、分页查询
-
在com.zzx.myes2.templatetest包下的TemplateTest类添加分页查询文档方法
// 分页查询文档 @Test public void searchDocumentPage(){ //1.确定查询方式 MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); //2.构建查询条件 //分页条件 PageRequest pageable = PageRequest.of(0, 1); NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQueryBuilder).withPageable(pageable).build(); //3.查询 SearchHits<Product> search = template.search(query, Product.class); //4.将查询结果封装为page对象 List<Product> products = new ArrayList<>(); for (SearchHit<Product> productSearchHit : search) { Product product = productSearchHit.getContent(); products.add(product); } /** * 封装Page对象,参数1:具体数据, 参数2:分页条件对象, 参数3:总条数 */ PageImpl<Product> page = new PageImpl<>(products, pageable, search.getTotalHits()); System.out.println("总条数:"+page.getTotalElements()); System.out.println("总页数:"+page.getTotalPages()); System.out.println("当前页面数据:"+page.getContent()); }
5、结果排序
- 在com.zzx.myes2.templatetest包下的TemplateTest类添加结果排序方法
//结果排序 @Test public void searchDocumentSort(){ //1.确定查询方式 MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); //2.构建查询条件 //排序条件 SortBuilder sortBuilder = SortBuilders.fieldSort("id").order(SortOrder.DESC); NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQueryBuilder).withSorts(sortBuilder).build(); //3.查询 SearchHits<Product> search = template.search(query, Product.class); //4.处理查询结果 for (SearchHit<Product> productSearchHit : search) { Product product = productSearchHit.getContent(); System.out.println(product); } }
总结:
- 1)使用Repository接口实现操作ElasticSearch,需要yml文件配置ES的主机和端口号,用一个接口去继承ElasticsearchRepository类,调用该类提供的方法即可。
2)DSL实现的话,用一个接口去继承ElasticsearchRepository类,通过@Query注解编写DSL语句,调用@Query注解下的方法即可。
3)按照规则命名方法查询,既不用编写DSL语句,也不用使用固定的方法,而是根据查询的需要按照规则命令该方法即可查询。命名以findBy开头。
4)分页查询时,需要使用Pageable类。
结果排序时,需要使用Sort类。 - 1)使用SpringDataES的ElasticsearchRestTemplate工具类操作索引时,需要先获取索引对象IndexOperations,再操作索引。
2)ElasticsearchRestTemplate增加或修改文档用save方法,删除用delete,查询用search。
复杂文档查询需要创建多条件查询构造器BoolQueryBuilder,通过往该构造器中添加查询条件即可,添加的方式有must、should、mustNot三种。
3)分页查询文档,在构建查询条件时指定分页条件PageRequest对象,将查询结果和分页条件对象以及查询结果的总条数传入PageImpl对象中。
4)对查询结果排序,使用SortBuilder构建排序条件,再添加到查询语句中。