springboot整合elasticsearch

写在前面

https://blog.csdn.net/qq_36357242/article/details/107997372 先看这篇文章完成docker安装elasticsearch

之前看过一篇大佬文章,但是文章现在需要vip才可以查看,所以我重新总结一下。windows的小伙伴也可以安装docker,或者直接安装elasticsearch也是可以的,yml配置需要改一下。

 

springboot整合elasticsearch

pom引入

<!--elasticsearch-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>3.1.6.RELEASE</version>
    <scope>compile</scope>
</dependency>

yml配置

spring:
  data:
    elasticsearch:
      cluster-name: docker-cluster #集群名称
      cluster-nodes: ip:9300 #配置es节点信息,逗号分隔,如果没有指定,则启动ClientNode
      properties:
        path:
          logs: ./elasticsearch/log #elasticsearch日志存储目录
          data: ./elasticsearch/data #elasticsearch数据存储目录

配置只需这么些,接下来就写一些demo来玩一下elaseticsearch

构建Item类

@Document(indexName = "item",type = "docs", shards = 1, replicas = 0)
public class Item {
    @Id
    private Long id;
    //文章使用分词器
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title; //标题
    @Field(type = FieldType.Keyword)
    private String category;// 分类
    @Field(type = FieldType.Keyword)
    private String brand; // 品牌
    @Field(type = FieldType.Double)
    private Double price; // 价格
    
}

创建ItemRepository并继承ElasticsearchRepository,有兴趣的可以看一下底层源码

public interface ItemRepository extends ElasticsearchRepository<Item,Long>{
    /**
     * @Description:根据价格区间查询  自定义查询
     * @Param price1
     * @Param price2
     * @Author: https://blog.csdn.net/chen_2890
     */
    List<Item> findByPriceBetween(double price1, double price2);

    List<Item> findByTitle(String title1);

    List<Item> findByTitleIn(Collection<String> ss);

}

创建索引

@RunWith(SpringRunner.class)
@SpringBootTest(classes = BootApplication.class)
public class EsDemoApplicationTest{

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;


    /**
     * @Description:创建索引,会根据Item类的@Document注解信息来创建
     */
    @Test
    public void testCreateIndex() {
        elasticsearchTemplate.createIndex(Item.class);
    }

    /**
     * @Description:删除索引
     */
    @Test
    public void testDeleteIndex() {
        elasticsearchTemplate.deleteIndex(Item.class);
    }

}

先执行创建索引

 索引数据操作

此处不多描述,注解已经写明。此处再次贴出原作者经典文章https://blog.csdn.net/chen_2890/article/details/83895646#t7

@RunWith(SpringRunner.class)
@SpringBootTest(classes = BootApplication.class)
public class ceshiTest {
    @Autowired
    private ItemRepository itemRepository;

    /**
     * @Description:定义新增方法
     */
    @Test
    public void insert() {
        Item item = new Item(1L, "小米手机7", " 手机",
                "小米", 3499.00);
        itemRepository.save(item);
    }



    /**
     * @Description:定义批量新增方法
     */
    @Test
    public void insertList() {
        List<Item> list = new ArrayList<>();
        list.add(new Item(1L, "小米9", "手机", "小米", 3299.00));
        list.add(new Item(2L, "华为pro30", "手机", "华为", 3999.00));
        list.add(new Item(3L, "一加7", "手机", "一加", 2999.00));
        list.add(new Item(4L, "魅族16", "手机", "魅族", 1999.00));
        list.add(new Item(5L, "苹果xs", "手机", "苹果", 5099.00));
        list.add(new Item(6L, "360pro", "手机", "360", 1099.00));
        list.add(new Item(7L, "荣耀V10", "手机", "华为", 899.00 ));
        // 接收对象集合,实现批量新增
        itemRepository.saveAll(list);
    }

    /**
     * @Description:按照价格区间查询  自定义方法
     * 自定义方法
        Spring Data 的另一个强大功能,是根据方法名称自动实现功能。
        比如:你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。
        当然,方法名称要符合一定的约定  下边为约定
            And	findByNameAndPrice
            Or	findByNameOrPrice
            Is	findByName
            Not	findByNameNot
            Between	findByPriceBetween
            LessThanEqual	findByPriceLessThan
            GreaterThanEqual	findByPriceGreaterThan
            Before	findByPriceBefore
            After	findByPriceAfter
            Like	findByNameLike
            StartingWith	findByNameStartingWith
            EndingWith	findByNameEndingWith
            Contains/Containing	findByNameContaining
            In	findByNameIn(Collection<String>names)
            NotIn	findByNameNotIn(Collection<String>names)
            Near	findByStoreNear
            True	findByAvailableTrue
            False	findByAvailableFalse
            OrderBy	findByAvailableTrueOrderByNameDesc
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void queryByPriceBetween(){
        List<Item> list = this.itemRepository.findByPriceBetween(2000.00, 3500.00);
        for (Item item : list) {
            System.out.println("item = " + item.getTitle());
        }
    }


    @Test
    public void queryByTitle(){
        List<Item> list = this.itemRepository.findByTitle("华为");
        for (Item item : list) {
            System.out.println("item = " + item.getTitle());
        }
    }

    @Test
    public void queryByTitleTo(){
        Collection<String> ss =  new ArrayList<>();
        ss.add("华为");
        ss.add("小米");
        List<Item> list = this.itemRepository.findByTitleIn(ss);
        for (Item item : list) {
            System.out.println("item = " + item.getTitle());
        }
    }

    /**
     * @Description:matchQuery底层采用的是词条匹配查询
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testMatchQuery(){
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", "华为"));
        // 搜索,获取结果
        Page<Item> items = this.itemRepository.search(queryBuilder.build());
        // 总条数
        long total = items.getTotalElements();
        System.out.println("获取的总条数 = " + total);
        for (Item item : items) {
            System.out.println("手机名称是:"+item.getTitle());
        }
    }


    /**
     * @Description:
     * termQuery:功能更强大,除了匹配字符串以外,还可以匹配
     * int/long/double/float/....
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testTermQuery(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withQuery(QueryBuilders.termQuery("price",1099));
        // 查找
        Page<Item> page = this.itemRepository.search(builder.build());

        for(Item item:page){
            System.out.println("手机是:"+item.getTitle());
        }
    }
    /**
     * @Description:布尔查询  多条件查询
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testBooleanQuery(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        builder.withQuery(
                QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("title","华为"))
                        .must(QueryBuilders.matchQuery("brand","华为"))
        );

        // 查找
        Page<Item> page = this.itemRepository.search(builder.build());
        for(Item item:page){
            System.out.println("手机名称是"+item.getTitle());
        }
    }


    /**
     * @Description:布尔查询  多条件查询
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testBlQuery(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        builder.withQuery(
                QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("title","荣耀"))
                        .must(QueryBuilders.matchQuery("title","华为"))
        );

        // 查找
        Page<Item> page = this.itemRepository.search(builder.build());
        for(Item item:page){
            System.out.println("手机名称是"+item.getTitle());
        }
    }
    /**
     * @Description:模糊查询
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testFuzzyQuery(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withQuery(QueryBuilders.fuzzyQuery("title","一"));
        Page<Item> page = this.itemRepository.search(builder.build());
        for(Item item:page){
            System.out.println("手机名称是:"+item.getTitle());
        }

    }

    /**
     * @Description:分页查询
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void searchByPage(){
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
        // 分页:
        int page = 0;
        int size = 2;
        queryBuilder.withPageable(PageRequest.of(page,size));

        // 搜索,获取结果
        Page<Item> items = this.itemRepository.search(queryBuilder.build());
        // 总条数
        long total = items.getTotalElements();
        System.out.println("总条数 = " + total);
        // 总页数
        System.out.println("总页数 = " + items.getTotalPages());
        // 当前页
        System.out.println("当前页:" + items.getNumber());
        // 每页大小
        System.out.println("每页大小:" + items.getSize());

        for (Item item : items) {
            System.out.println(item.getTitle());
        }
    }

    /**
     * @Description:排序查询
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void searchAndSort(){
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));

        // 排序
        queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));

        // 搜索,获取结果
        Page<Item> items = this.itemRepository.search(queryBuilder.build());
        // 总条数
        long total = items.getTotalElements();
        System.out.println("总条数 = " + total);

        for (Item item : items) {
            System.out.println("手机的价格是:"+item.getTitle()+":"+item.getPrice());
        }
    }

    /**
     * @Description:按照品牌brand进行分组
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testAgg(){
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
        queryBuilder.addAggregation(
                AggregationBuilders.terms("brands").field("brand"));
        // 2、查询,需要把结果强转为AggregatedPage类型
        AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
        // 3、解析
        // 3.1、从结果中取出名为brands的那个聚合,
        // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
        StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
        // 3.2、获取桶
        List<StringTerms.Bucket> buckets = agg.getBuckets();
        // 3.3、遍历
        for (StringTerms.Bucket bucket : buckets) {
            // 3.4、获取桶中的key,即品牌名称
            System.out.println(bucket.getKeyAsString());
            // 3.5、获取桶中的文档数量
            System.out.println(bucket.getDocCount());
        }

    }


    /**
     * @Description:嵌套聚合,求平均值
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Test
    public void testSubAgg(){
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
        queryBuilder.addAggregation(
                AggregationBuilders.terms("brands").field("brand")
                        .subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶内进行嵌套聚合,求平均值
        );
        // 2、查询,需要把结果强转为AggregatedPage类型
        AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
        // 3、解析
        // 3.1、从结果中取出名为brands的那个聚合,
        // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
        StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
        // 3.2、获取桶
        List<StringTerms.Bucket> buckets = agg.getBuckets();
        // 3.3、遍历
        for (StringTerms.Bucket bucket : buckets) {
            // 3.4、获取桶中的key,即品牌名称  3.5、获取桶中的文档数量
            System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "台");

            // 3.6.获取子聚合结果:
            InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
            System.out.println("平均售价:" + avg.getValue());
        }

    }


}

大致的demo就是以上的情况。

问题

但是项目在启动过程中回报一个错误,

Timeout connecting to [localhost/127.0.0.1:9200]

明明已经连接到远端es,但还会出现这个问题。

解决,

spring:
  data:
    elasticsearch:
      cluster-name: docker-cluster
      cluster-nodes: ip:9300 #配置es节点信息,逗号分隔,如果没有指定,则启动ClientNode
      properties:
        path:
          logs: ./elasticsearch/log #elasticsearch日志存储目录
          data: ./elasticsearch/data #elasticsearch数据存储目录
  elasticsearch:
    rest:
      uris: ["ip:9200"]

即可。

 

加入我们

如果有需要,欢迎可以加入我们的QQ群!(QQ搜索 1074281704, 加入我们的QQ群吧!)
有任何问题,也可以加入我们的QQ群,欢迎交(che)流(dan)!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

答 案

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值