整合ElasticSearch
一、引入依賴及配置
1、引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2、配置yml
spring:
data:
elasticsearch:
cluster-name: elasticsearch # 集羣名字
cluster-nodes: localhost:9300 # 集羣結點,多個節點用逗號隔開
二、Repository接口的使用
Repository
就是ES的Dao
,和JPA的裏的用法大致一樣。
1、創建實體類
這裏以Article
類爲例,介紹了註解
常用的用法,更多用法可以百度~
@Data // lombok生成get/set
// indexName:ElasticSearch裏的索引名 type:類型名
@Document(indexName = "lcy_article",type = "article")
public class Article {
@Id // Id標識主鍵
// Field標識屬性,type:屬性類型,store:是否存儲,默認否,index:是否索引,默認是,analyzer:分詞的方式
@Field(type = FieldType.Long,store = true)
private Long id;
@Field(type = FieldType.Keyword,store = true)
private String author;
@Field(type = FieldType.Text,store = true,analyzer = "ik_smart")
private String title;
@Field(type = FieldType.Text,store = true,analyzer = "ik_smart")
private String content;
@Field(type = FieldType.Integer,store = true)
private Integer price;
public Article() {
}
public Article(Long id, String author, String title, String content,Integer price) {
this.id = id;
this.author = author;
this.title = title;
this.content = content;
this.price = price;
}
@Override
public String toString() {
return "ID:" + id + "\t\t標題:" + title + "\t\t作者:" + author + "\t\t內容:" + content;
}
}
2、繼承ElasticSearchRepository
接口
// ElasticsearchRepository<文檔類型,主鍵類型>
public interface ArticleRepository extends ElasticsearchRepository<Article,Long> {
// 自定義查詢 - 符合方法命名規範即可
List<Article> findByTitle(String title);
List<Article> findByIdBetween(Long start,Long end);
}
啓動類上需要添加EnableElasticsearchRepositories
註解掃描Repository
接口。
@SpringBootApplication
@EnableElasticsearchRepositories(basePackages = "pers.liuchengyin.es.repository") // 配置ES掃描repository的包
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
3、測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class ArticleTest {
@Autowired
private ElasticsearchTemplate template;
@Autowired
private ArticleRepository articleRepository;
/******************************************* 索引操作start *****************************************/
/**
* 創建索引並配置映射關係
*/
@Test
public void createIndex(){
template.createIndex(Article.class);
}
/**
* 配置映射關係 - 把類中的屬性與es內部的對應
*/
@Test
public void createMapping(){
template.putMapping(Article.class);
}
/**
* 刪除索引
*/
@Test
public void deleteIndex(){
template.deleteIndex(Article.class);
}
/******************************************* 索引操作end *****************************************/
/******************************************* 文檔基本操作Repository start *****************************************/
/**
* 新增/修改文檔
* ES沒有提供修改的方法,只能通過新增的方式去完成修改
* 也就是說實際上是先刪除,後新增的方式,需要保證主鍵Id一致
*/
@Test
public void addOrUpdateDocument(){
Article article = new Article(7L, "柳成蔭", "Java高併發", "高併發很難啊",100);
articleRepository.save(article);
Article article6 = new Article(1L, "柳成蔭", "Java基礎", "Java基礎要學紮實",90);
Article article1 = new Article(2L, "九月清晨", "Java高級", "一、集合框架及泛型1、集合框架是一套性能優良、使用方便的接口和類",100);
Article article2 = new Article(3L, "尋寶遊戲", "SSM框架", "SSM框架提高了人們寫代碼的效率",100);
Article article3 = new Article(4L, "尋夢港", "SpringBoot框架", "SpringBoot框架在SSM的基礎之上更進一層,省略了很多配置",100);
Article article4 = new Article(5L, "祖龍城", "SOA架構", "SOA架構解決了服務相關的問題",100);
Article article5 = new Article(6L, "不如喫茶去", "微服務架構", "微服務在SOA之上,將服務更加細緻化",100);
List<Article> articles = new ArrayList<>();
articles.add(article1);
articles.add(article2);
articles.add(article3);
articles.add(article4);
articles.add(article5);
articles.add(article6);
articleRepository.saveAll(articles);
}
/**
* 根據Id刪除文檔
* 還可以直接傳入文檔刪除,批量刪除,全部刪除等
*/
@Test
public void deleteDocument(){
articleRepository.deleteById(1L);
}
/**
* 分頁查詢
* 如果不是查詢所有,會自動分頁,10條數據
*/
@Test
public void selectPage(){
Page<Article> all = articleRepository.findAll(PageRequest.of(0, 3));
all.forEach(System.out::println);
}
/**
* 按指定字段排序
*/
@Test
public void selectSort(){
Iterable<Article> articles = articleRepository.findAll(Sort.by("id").ascending());
articles.forEach(System.out::println);
}
/**
* 自定義查詢 - 根據Title查詢
* 先分詞後查詢
*/
@Test
public void selectByTerm(){
List<Article> articles = articleRepository.findByTitle("Java");
articles.forEach(System.out::println);
}
/**
* 自定義查詢 - 根據Id範圍查詢
*/
@Test
public void selectByIdScope(){
List<Article> articles = articleRepository.findByIdBetween(3L,5L);
articles.forEach(System.out::println);
}
/******************************************* 文檔基本操作Repository end *****************************************/
/******************************************* 文檔基本操作NativeSearchQuery start *****************************************/
/**
* 詞條查詢 - 精準查詢
*/
@Test
public void termSearch(){
// 創建查詢條件構建器
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
// 詞條查詢 - 根據Id查詢
nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("id",1L));
// 構建查詢
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 匹配查詢
*/
@Test
public void matchSearch(){
// 創建查詢條件構建器
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title","Java"));
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 布爾查詢
*/
@Test
public void boolSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder
.withQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("title", "Java"))
.must(QueryBuilders.termQuery("id", 1L)));
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 模糊查詢
* 需要注意的是 - 可能是因爲中文分詞器的原因,對於英文模糊搜索無結果
* ? 表示一個未知的佔位符
* * 表示0到n個任意佔位符
*/
@Test
public void vagueSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(QueryBuilders.wildcardQuery("title","*架*"));
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 分頁查詢 - 在模糊查詢的基礎上進行
*/
@Test
public void pageSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(QueryBuilders.wildcardQuery("title","*架*"));
// 分頁
nativeSearchQueryBuilder.withPageable(PageRequest.of(0,3));
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 排序查詢 - 在模糊查詢的基礎上進行
*/
@Test
public void sortSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(QueryBuilders.wildcardQuery("title","*架*"));
// 按Id倒序排序
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 過濾查詢 - 不會計算匹配分
*/
@Test
public void filterSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(QueryBuilders.boolQuery().filter(QueryBuilders.matchQuery("author","柳")));
Page<Article> articles = articleRepository.search(nativeSearchQueryBuilder.build());
articles.forEach(System.out::println);
}
/**
* 聚合(分組)查詢
* 注意要分組的字段類型要爲 keyword
*/
@Test
public void aggregationSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
// 添加聚合,聚合類型爲terms,聚合名稱爲authors,聚合字段爲author
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("authors").field("author"));
// 查詢(結果改爲聚合類分頁結果)
AggregatedPage<Article> articles = (AggregatedPage<Article>) articleRepository.search(nativeSearchQueryBuilder.build());
// 在查詢結果中找到聚合 - 根據聚合名稱
StringTerms author = (StringTerms) articles.getAggregation("authors");
// 獲取查詢到的桶(分組)
List<StringTerms.Bucket> buckets = author.getBuckets();
// 遍歷桶
for (StringTerms.Bucket bucket : buckets) {
// 獲取桶的Key
String keyAsString = bucket.getKeyAsString();
// 獲取桶的數量(文檔的數量)
long docCount = bucket.getDocCount();
System.out.println(keyAsString + ":" + docCount);
}
}
@Test
public void sonAggregationSearch(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("authors").field("author")
// 創建子聚合工程 - 對父聚合工廠的結果進行取平均值 - price
.subAggregation(AggregationBuilders.avg("avg").field("price")));
// 查詢(結果改爲聚合類分頁結果)
AggregatedPage<Article> articles = (AggregatedPage<Article>) articleRepository.search(nativeSearchQueryBuilder.build());
// 在查詢結果中找到聚合 - 根據聚合名稱
StringTerms authors = (StringTerms) articles.getAggregation("authors");
// 獲取查詢到的桶(分組)
List<StringTerms.Bucket> buckets = authors.getBuckets();
// 遍歷
for (StringTerms.Bucket bucket : buckets) {
// 獲取父聚合字段名及文檔數
System.out.println(bucket.getKeyAsString() + ":" + bucket.getDocCount());
System.out.println();
// 獲取桶對應的avg
InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("avg");
System.out.println("平均price是:" + avg.getValue());
}
}
/******************************************* 文檔基本操作NativeSearchQuery end *****************************************/
}
本文主要是Repository
的使用,實際上ElasticsearchTemplate
基本也能完成Repository
提供的功能。更多關於ElasticsearchTemplate
的使用可以百度,我這裏就不做演示了(主要是我也沒怎麼了解hhh)。