增删改
添加
- 修改
ArticleService
添加一个方法做添加
java
public void save(Article article){
article.setId(UUID.randomUUID().toString());
articleDao.save(article);
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class EsApplicationTests {
private ArticleService articleService;
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
代码如下:
java
/**
* @author BNTang
**/
public class ArticleService {
private ArticleDao articleDao;
public void update(Article article) {
if (StringUtils.isEmpty(article.getId())) {
throw new RuntimeException("ID不能为空");
}
articleDao.save(article);
}
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class EsApplicationTests {
private ArticleService articleService;
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
java
/**
* @author BNTang
**/
public class ArticleService {
private ArticleDao articleDao;
public void saveBatch(List<Article> articles) {
articleDao.saveAll(articles);
}
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class EsApplicationTests {
private ArticleService articleService;
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
java
/**
* @author BNTang
**/
public class ArticleService {
private ArticleDao articleDao;
public void deleteById(String id) {
articleDao.deleteById(id);
}
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class ArticleService {
private ArticleDao articleDao;
public void deleteById(String id) {
articleDao.deleteById(id);
}
}
查询
- 根据
id
查询 - 修改
ArticleService
java
/**
* @author BNTang
**/
public class ArticleService {
private ArticleDao articleDao;
public Article getById(String id) {
return articleDao.findById(id).get();
}
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class EsApplicationTests {
private ArticleService articleService;
public void getById() {
Article article = articleService.getById("7dwWSXUBaFv6dXD8PRwo");
System.out.println(article);
}
}
JPA语法查询
Keyword |
Sample |
Elasticsearch Query String |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 根据
content
查询- 这里如果是需要分词的字段
- 首先会将传入的参数进行分词
- 分完词之后,使用这些分词进行查询
- 然后取交集
- 其实就是相当于
- 分词之后多个
term
取交集- 修改
ArticleDao
- Dao层
java
/**
* @author BNTang
**/
public interface ArticleDao extends ElasticsearchRepository<Article, String> {
List<Article> findByContent(String content);
}
- Service层
- 修改
ArticleService
java
/**
* @author BNTang
**/
public class ArticleService {
private ArticleDao articleDao;
public List<Article> getByContent(String content) {
return articleDao.findByContent(content);
}
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class EsApplicationTests {
private ArticleService articleService;
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
**/
public class ArticleService {
private ArticleDao articleDao;
public List<Article> getByContentLike(String content) {
return articleDao.findByContentLike(content);
}
}
- 测试类代码如下:
java
/**
* @author BNTang
**/
public class EsApplicationTests {
private ArticleService articleService;
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
**/
public class ArticleService {
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
**/
public class EsApplicationTests {
private ArticleService articleService;
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层
java
/**
* @author BNTang
**/
public class ArticleService {
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
**/
public class EsApplicationTests {
private ArticleService articleService;
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
**/
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
**/
public class ArticleService {
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
**/
public class EsApplicationTests {
private ArticleService articleService;
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
**/
public class ArticleService {
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
**/
public class EsApplicationTests {
private ArticleService articleService;
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
**/
public class ArticleService {
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
**/
public class EsApplicationTests {
private ArticleService articleService;
public void getCountByType() {
articleService.getCountByTypes();
}
}
- ????嵌套聚合
- Service层,修改
ArticleService
java
/**
* @author BNTang
**/
public class ArticleService {
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
**/
public class EsApplicationTests {
private ArticleService articleService;
public void getCountAndSum() {
articleService.getCountAndSum();
}
}