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

发布了100 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40885085/article/details/105023026