SpringBoot - 整合ElasticSearch及基本使用

整合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)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章