SpringData-ESCRUD
  TEZNKK3IfmPf 2023年11月14日 19 0

添加

  • 修改​​ArticleService​​ 添加一个方法做添加

SpringData-ESCRUD

java

public void save(Article article){
article.setId(UUID.randomUUID().toString());
articleDao.save(article);
}

 

  • 测试类代码如下:

 

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void save() {
Article article = new Article();
article.setAuthor("BNTang");
article.setTitle("Java从入门到精通");
article.setContent("PHP是世界上最好的语言,奥利给");
article.setRead(500);
article.setTypes("Java");
articleService.save(article);
}
}

修改

  • 当数据存在时是更新,当数据不存在时,是修改
  • 修改​​ArticleService​​ 代码如下:

SpringData-ESCRUD

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;

public void update(Article article) {
if (StringUtils.isEmpty(article.getId())) {
throw new RuntimeException("ID不能为空");
}
articleDao.save(article);
}
}
  • 测试类代码如下:

SpringData-ESCRUD

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void update() {
Article article = new Article();
article.setId("7f4eaee6-9cf4-4af0-a02e-ed666077ecd2");
article.setAuthor("BNTang");
article.setTitle("PHP是世界上最好的语言");
article.setContent("学习不可三天打鱼两天晒网,打铁还需自身硬");
article.setRead(600);
article.setTypes("PHP");
articleService.update(article);
}
}

批量新增

  • 修改​​ArticleService​

SpringData-ESCRUD

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;

public void saveBatch(List<Article> articles) {
articleDao.saveAll(articles);
}
}
  • 测试类代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void saveBatch() {
Article article = new Article();
article.setAuthor("BNTang");
article.setTitle("文档1");
article.setContent("我是文档1");
article.setRead(600);
article.setTypes("PHP");

Article article2 = new Article();
article2.setAuthor("BNTang");
article2.setTitle("文档2");
article2.setContent("我是文档2");
article2.setRead(600);
article2.setTypes("PHP");

List<Article> list = new ArrayList<>();
list.add(article);
list.add(article2);

articleService.saveBatch(list);
}
}

删除

  • 根据​​id​​ 删除
  • 修改​​ArticleService​

SpringData-ESCRUD

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;

public void deleteById(String id) {
articleDao.deleteById(id);
}
}
  • 测试类代码如下:

SpringData-ESCRUD

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;

public void deleteById(String id) {
articleDao.deleteById(id);
}
}

查询

  • 根据​​id​​ 查询
  • 修改​​ArticleService​

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;

public Article getById(String id) {
return articleDao.findById(id).get();
}
}

 

  • 测试类代码如下:

 

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void getById() {
Article article = articleService.getById("7dwWSXUBaFv6dXD8PRwo");
System.out.println(article);
}
}

JPA语法查询

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" : "?"}}}}​

​Between​

​findByPriceBetween​

​{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}​

​LessThanEqual​

​findByPriceLessThan​

​{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}​

​GreaterThanEqual​

​findByPriceGreaterThan​

​{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"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}}}}}​

​Contains/Containing​

​findByNameContaining​

​{"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" : "?"}}}}}}​

​Near​

​findByStoreNear​

​Not Supported Yet !​

​True​

​findByAvailableTrue​

​{"bool" : {"must" : {"field" : {"available" : true}}}}​

​False​

​findByAvailableFalse​

​{"bool" : {"must" : {"field" : {"available" : false}}}}​

​OrderBy​

​findByAvailableTrueOrderByNameDesc​

​{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}​

 

  • 根据​​content​​ 查询
  • 这里如果是需要分词的字段
  • 首先会将传入的参数进行分词
  • 分完词之后,使用这些分词进行查询
  • 然后取交集
  • 其实就是相当于
  • 分词之后多个​​term​​ 取交集
  • 修改​​ArticleDao​
  • Dao层

java

/**
* @author BNTang
**/
public interface ArticleDao extends ElasticsearchRepository<Article, String> {
List<Article> findByContent(String content);
}
  • Service层
  • 修改​​ArticleService​

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;
public List<Article> getByContent(String content) {
return articleDao.findByContent(content);
}
}
  • 测试类代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void content() {
List<Article> list = articleService.getByContent("干就完了,奥利给");
System.out.println(list);
}
}
  • 根据 content 查询
  • 这里会将 content 进行分词
  • 根据分词的结果进行查询
  • 取并集
  • 其实就是相当于​​match​
  • 修改​​ArticleDao​
  • Dao层

java

/**
* @author BNTang
**/
public interface ArticleDao extends ElasticsearchRepository<Article, String> {
List<Article> findByContentLike(String content);
}
  • Service层

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;
public List<Article> getByContentLike(String content) {
return articleDao.findByContentLike(content);
}
}
  • 测试类代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void contentLike() {
List<Article> articleList = articleService.getByContentLike("老铁,奥利给");
System.out.println(articleList);
}
}

分页查询

  • 分页查询主要涉及到两个类
  • 一个是​​Page​
  • 一个是​​Pageable​
  • 根据 content 和 title 分页查询
  • 修改​​ArticleDao​
  • Dao层

java

/**
* @author BNTang
**/
public interface ArticleDao extends ElasticsearchRepository<Article, String> {
Page<Article> findByContentLikeOrTitleLike(String content, String title, Pageable pageable);
}
  • Service层

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;

public Page<Article> getByContentOrTitlePage(String content, String title, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Article> articlePage = articleDao.findByContentLikeOrTitleLike(content, title, pageable);
return articlePage;
}
}
  • 测试类代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void testPage1() {
Page<Article> page = articleService.getByContentOrTitlePage("奥利给", "PHP", 1, 2);
System.out.println("总条数:" + page.getTotalElements());
System.out.println("总页数:" + page.getTotalPages());
System.out.println("本页数据:" + page.getContent());
}
}

高级查询

  • 虽然基本查询和自定义方法已经很强大了
  • 但是如果是复杂查询(模糊、通配符、词条查询等)就显得力不从心了
  • 此时,我们只能使用原生查询

基本查询

  • 先来看看基本的玩法
  • 修改​​ArticleService​
  • Service层

SpringData-ESCRUD

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

public List<Article> getByContentNative(String content) {
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("content", content);

NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
queryBuilder.withQuery(matchQueryBuilder);

SearchHits<Article> searchHits = elasticsearchRestTemplate.search(queryBuilder.build(), Article.class);
return searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
}
}
  • 测试代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void getByContentNative() {
List<Article> articleList = articleService.getByContentNative("干就完了,奥利给");
System.out.println(articleList);
}
}
  • ​QueryBuilders​​ 提供了大量的静态方法
  • 用于生成各种不同类型的查询对象,例如:词条、模糊、通配符等​​QueryBuilder​​ 对象
  • ​NativeSearchQueryBuilder​​:是 Spring 提供的一个查询条件构建器,帮助构建 JSON 格式的请求体

分页查询

  • 利用​​NativeSearchQueryBuilder​​ 可以很方便的实现分页:
  • 在​​top.it6666.dao​​​ 中创建一个​​Page​​ 类,代码如下:

java

/**
* @author BNTang
**/
@Data
@NoArgsConstructor
public class Page<T> {

private Long totalCount;

private Integer totalPage;

private List<T> list;
public Page(Long totalCount, List<T> list) {
this.totalCount = totalCount;
this.list = list;
}

public Page(Long totalCount, Integer size, List<T> list) {
this.totalCount = totalCount;
this.list = list;
// 计算总页数
this.totalPage = (int) Math.ceil(totalCount * 1.0 / size);
}
}
  • 修改​​ArticleService​
  • Service层

java

/**
* @author BNTang
**/
@Service
public class ArticleService {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

public Page<Article> getPageByContentNative(String content, String title, int page, int size) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

// 构造queryBuilder
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.matchQuery("content", content));
boolQueryBuilder.should(QueryBuilders.matchQuery("title", title));

queryBuilder.withQuery(boolQueryBuilder);
queryBuilder.withPageable(PageRequest.of(page - 1, size));
SearchHits<Article> searchHits = elasticsearchRestTemplate.search(queryBuilder.build(), Article.class);

// 获取查询的数据
List<Article> articleList = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());

// 获取总条数
long totalHits = searchHits.getTotalHits();
return new Page<Article>(totalHits, size, articleList);
}
}

测试类代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void getPageByContentNative() {
Page<Article> page = articleService.getPageByContentNative("奥利给,Java,PHP,文档", "奥利给,Java,PHP,文档", 1, 2);
System.out.println("总条数:" + page.getTotalCount());
System.out.println("总页数:" + page.getTotalPage());
System.out.println("本页数据:");
page.getList().forEach(System.out::println);
}
}
  • 可以发现,Elasticsearch 中的分页是从第 0 页开始

排序查询

  • 排序也能通过​​NativeSearchQueryBuilder​​ 来完成:
  • 修改​​ArticleService​
  • Service层

java

/**
* @author BNTang
**/
@Service
public class ArticleService {

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

public Page<Article> getPageByContentNativeSort(String content, String title, int page, int size) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

// 构造queryBuilder
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.matchQuery("content", content));
boolQueryBuilder.should(QueryBuilders.matchQuery("title", title));

queryBuilder.withQuery(boolQueryBuilder);
queryBuilder.withPageable(PageRequest.of(page - 1, size));

// 构造排序对象
queryBuilder.withSort(SortBuilders.fieldSort("read").order(SortOrder.DESC));

SearchHits<Article> searchHits = elasticsearchRestTemplate.search(queryBuilder.build(), Article.class);

// 获取查询的数据
List<Article> articleList = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());

// 获取总条数
long totalHits = searchHits.getTotalHits();
return new Page<Article>(totalHits, size, articleList);
}
}

测试类代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void getPageByContentNativeSort() {
Page<Article> page = articleService.getPageByContentNativeSort("奥利给,Java,PHP,文档", "奥利给,Java,PHP,文档", 1, 2);
System.out.println("总条数:" + page.getTotalCount());
System.out.println("总页数:" + page.getTotalPage());
System.out.println("本页数据:");
page.getList().forEach(System.out::println);
}
}

聚合查询

  • 聚合为桶
  • 桶就是分组,比如这里我们按照帖子分类进行分组:
  • Service层,修改​​ArticleService​

java

/**
* @author BNTang
**/
@Service
public class ArticleService {

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

public void getCountByTypes() {
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

// 设置要查询的字段
nativeSearchQueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));

// 设置一下查询的条数
nativeSearchQueryBuilder.withPageable(PageRequest.of(0, 1));

// 设置聚合字段,指定聚合后的字段名,以及根据哪个字段聚合
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("typeCount").field("types"));

// 搜索
SearchHits<Article> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Article.class);

// 取出来聚合的数据
Aggregations aggregations = searchHits.getAggregations();

// 取出我们聚合的字段
Terms terms = aggregations.get("typeCount");
List<? extends Terms.Bucket> buckets = terms.getBuckets();
for (Terms.Bucket bucket : buckets) {
System.out.println(bucket.getKey());
System.out.println(bucket.getDocCount());
}

}
}

测试代码如下:

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void getCountByType() {
articleService.getCountByTypes();
}
}
  • ????嵌套聚合
  • Service层,修改​​ArticleService​

java

/**
* @author BNTang
**/
@Service
public class ArticleService {

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

public void getCountAndSum() {
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

// 设置要查询的字段
nativeSearchQueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));

// 设置一下查询的条数
nativeSearchQueryBuilder.withPageable(PageRequest.of(0, 1));

// 设置聚合字段,指定聚合后的字段名,以及根据哪个字段聚合
nativeSearchQueryBuilder.addAggregation(
// 按照types聚合,求总数
AggregationBuilders.terms("typeCount").field("types")
// types聚合完毕后,再根据read聚合
.subAggregation(AggregationBuilders.sum("readNum").field("read"))
);

// 搜索
SearchHits<Article> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Article.class);
Aggregations aggregations = searchHits.getAggregations();
Terms terms = aggregations.get("typeCount");
List<? extends Terms.Bucket> buckets = terms.getBuckets();
for (Terms.Bucket bucket : buckets) {
System.out.println(bucket.getKey());
System.out.println(bucket.getDocCount());
Aggregations subAggs = bucket.getAggregations();
Sum sum = subAggs.get("readNum");
System.out.println(sum.getValue());
}
}
}
  • 测试代码如下

java

/**
* @author BNTang
**/
@SpringBootTest
public class EsApplicationTests {

@Autowired
private ArticleService articleService;

@Test
public void getCountAndSum() {
articleService.getCountAndSum();
}
}
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月14日 0

暂无评论

TEZNKK3IfmPf