springboot整合elasticsearch

springboot整合elasticsearch

1. ElasticsearchRestTemplate的使用

2. RestHgihLevelClient的使用

gitee:springboot整合elasticsearch

特别说明:
1.环境mysql,elasticsearch。如果没有数据可以使用,需要导入根目录下的goods到mysql中数据库es
2.如果只看RestHighLevelClient,可以直接在模块“springboot-resthighlevelclient”中进行查看相关的方法【目录4】

1.目录结构

springboot整合elasticsearch_第1张图片

2.maven依赖

2.1 父工程maven

    <modules>
        <module>springboot-resthighlevelclientmodule>
        <module>springboot-elasticsearchresttemplatemodule>
    modules>

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.4.5version>
    parent>

2.2子模块springboot-elasticsearchresttemplate

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <version>2.4.5version>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-elasticsearchartifactId>
            <version>2.4.5version>
        dependency>


        <dependency>
            <groupId>org.elasticsearch.clientgroupId>
            <artifactId>elasticsearch-rest-high-level-clientartifactId>
            <version>7.6.2version>
        dependency>
        <dependency>
            <groupId>org.elasticsearch.clientgroupId>
            <artifactId>elasticsearch-rest-clientartifactId>
            <version>7.6.2version>
        dependency>
        <dependency>
            <groupId>org.elasticsearchgroupId>
            <artifactId>elasticsearchartifactId>
            <version>7.6.2version>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.1.0version>
        dependency>

        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
        dependency>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.16version>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13.2version>
            <scope>testscope>
        dependency>

    dependencies>

2.3 子工程springboot-resthighlevelclient依赖

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <version>2.4.5version>
        dependency>

        <dependency>
            <groupId>org.elasticsearch.clientgroupId>
            <artifactId>elasticsearch-rest-high-level-clientartifactId>
        dependency>

        <dependency>
            <groupId>org.elasticsearch.clientgroupId>
            <artifactId>elasticsearch-rest-clientartifactId>
        dependency>

        <dependency>
            <groupId>org.elasticsearchgroupId>
            <artifactId>elasticsearchartifactId>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13.2version>
            <scope>testscope>
        dependency>
    dependencies>

3.子模块springboot-elasticsearchresttemplate

3.1 application.yaml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.153.133:3306/es?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root
  elasticsearch:
    rest:
      uris: http://192.168.153.133:9200

mybatis-plus:
  type-aliases-package: com.qq.es.pojo

3.2 es相关java实体对象

package com.qq.es.document;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * @author 黔程似景
 * @description 商品文档对象
 * @date 2023/6/17 12:07
 * @blame 黔程似景
 **/
@Data
@Document(indexName = "goods")
public class GoodsDocument {

    @Id
    private Long id;//把id字段作为文档主键

    //商品标题
    @Field(type = FieldType.Text , analyzer = "ik_smart")//指定问字段类型,分词器类型
    private String title;//title使用ik分词器分词

    //商品价格
    @Field(type = FieldType.Double)
    private Double price;

    //商品库存
    @Field(type = FieldType.Integer)
    private Integer num;

    //商品类别
    @Field(type = FieldType.Keyword)//此处为不用分词
    private String category;

    //品牌名称
    @Field(type = FieldType.Keyword)
    private String brand;
}

3.3 es操作ElasticsearchRepository(如mysql的mapper)

package com.qq.es.repository;

import com.qq.es.document.GoodsDocument;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * @author 黔程似景
 * @description es操作
 * @date 2023/6/17 12:07
 * @blame 黔程似景
 **/
public interface GoodsRepository extends ElasticsearchRepository<GoodsDocument,Long> {
}

3.4 mysql实体对象

package com.qq.es.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author 黔程似景
 * @description sql商品表
 * @date 2023/6/17 12:07
 * @blame 黔程似景
 **/
@Data
@TableName("goods")
public class Goods {
    //商品id
    @TableId(type = IdType.AUTO)
    private Long id;

    //商品标题
    private String title;

    //商品价格
    private Double price;

    //商品库存
    private Integer num;

    //商品类别
    private String category;

    //品牌名称
    private String brand;
}

3.5 mysql操作mapper(使用的mybatis-plus)

package com.qq.es.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qq.es.pojo.Goods;

/**
 * @author 黔程似景
 * @description 查询商品mapper
 * @date 2023/6/17 12:07
 * @blame 黔程似景
 **/
public interface GoodsMapper extends BaseMapper<Goods> {
}

3.6 类型转换工具

package com.qq.es.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 黔程似景
 * @description 类型转换工具
 * @date 2023/6/17 12:07
 * @blame 黔程似景
 **/
@Slf4j
public class BeanHelper {
    
    public static <T> T copyProperties(Object source, Class<T> target){
        try {
            T t = target.newInstance();

            BeanUtils.copyProperties(source, t);
            return t;
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错,目标对象{}构造函数异常", target.getName(), e);
            return null;
        }
    }

    public static <T> List<T> copyWithCollection(List<?> sourceList, Class<T> target){
        try {
            return sourceList.stream().map(s -> copyProperties(s, target)).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错,目标对象{}构造函数异常", target.getName(), e);
            return null;
        }

    }

    public static <T> Set<T> copyWithCollection(Set<?> sourceList, Class<T> target){
        try {
            return sourceList.stream().map(s -> copyProperties(s, target)).collect(Collectors.toSet());
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错,目标对象{}构造函数异常", target.getName(), e);
            return null;
        }
    }
}

3.7 启动类

package com.qq.es;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author 黔程似景
 * @description 启动类
 * @date 2023/6/17 11:45
 * @blame 黔程似景
 **/
@SpringBootApplication
public class ApplicationStarter {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationStarter.class , args);
    }
}

3.8 测试类(批量从mysql导入到es)

package com.qq.es.test.mapper;

import com.qq.es.document.GoodsDocument;
import com.qq.es.mapper.GoodsMapper;
import com.qq.es.pojo.Goods;
import com.qq.es.repository.GoodsRepository;
import com.qq.es.utils.BeanHelper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class GoodsTest {

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private GoodsRepository goodsRepository;

    /**
     * 批量导入
     */
    @Test
    public void testImportData(){
        //从mysql中读取数据
        List<Goods> goods = goodsMapper.selectList(null);

        System.out.println(goods.size());

        //2. 从goods对象转换成gooddocument对象集合
        List<GoodsDocument> goodsDocuments = BeanHelper.copyWithCollection(goods, GoodsDocument.class);

        //批量导入goodDocument对象
        goodsRepository.saveAll(goodsDocuments);
    }
}

3.9 测试es查询方法

package com.qq.es.test.mapper;


import com.qq.es.document.GoodsDocument;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.elasticsearch.search.aggregations.metrics.Max;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
@RunWith(SpringRunner.class)
public class SelectGoodsEsTest {

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    /*
        es查询所有数据
        get goods/_search
        {
            "query":{
                "match_all":{}
            }
        }
     */
    @Test
    public void testMatchAll() {
        //1. 创建查询构造器对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 在查询构造器中添加各种条件
        searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());

        //3. 创建查询对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 进行查询 searchHits:封装所有查询结果
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //处理结果
        List<GoodsDocument> list = new ArrayList<>();
        for (SearchHit<GoodsDocument> searchHit : searchHits) {
            GoodsDocument goodsDocument = searchHit.getContent();
            list.add(goodsDocument);
        }

        System.out.println("集合长度:" + list.size());
        System.out.println(list);
    }

    /*
        不分词查询查询term---------------->输入的是什么,就会搜什么,不进行分词
        # 精准查询包含某个词的文档
        GET goods/_search
        {
          "query": {
            "term": {
              "title": {
                "value": "老人"
              }
            }
          }
        }
     */
    @Test
    public void testTermQuery() {
        //1. 创建查询构造器对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入条件
        searchQueryBuilder.withQuery(QueryBuilders.termQuery("title", "老人"));

        //3. 创建查询对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 查询获取结果
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //5. 处理结果
        List<GoodsDocument> list = new ArrayList<>();
        for (SearchHit<GoodsDocument> searchHit : searchHits) {
            GoodsDocument goodsDocument = searchHit.getContent();

            System.out.println(goodsDocument);
            list.add(goodsDocument);
        }

        System.out.println("拿到:" + list.size() + "条数据");
    }

    /*
            # 对查询条件进行分词后查询,取并集
                GET goods/_search
                {
                  "query": {
                    "match": {
                      "title": "我要一部老人手机"
                    }
                  }
                }
     */
    @Test
    public void testMatchQuery() {
        //1. 创建查询构造器对象:用于查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件
        searchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", "我要一部老人手机"));

        //3. 创建查询条件对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //查询
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //获取数量
        System.out.println(searchHits.getTotalHits());

        //5. 处理结果
        List<GoodsDocument> list = new ArrayList<>();
        for (SearchHit<GoodsDocument> searchHit : searchHits) {
            GoodsDocument goodsDocument = searchHit.getContent();

            list.add(goodsDocument);
        }

        System.out.println("分词查询到" + list.size() + "条数据");
    }

    /*
            # 对查询条件进行分词后查询,取交集
                GET goods/_search
                {
                  "query": {
                    "match": {
                      "title": {
                        "query": "老人手机",
                        "operator": "and"
                      }
                    }
                  }
                }
     */
    @Test
    public void testMatchAndQuery() {
        //1. 创建查询条件构造器对象:用于查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件
        searchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", "老人手机").operator(Operator.AND));

        //3. 创建查询条件对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 根据查询条件,查询结果
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //5. 查询数据条数
        System.out.println("分词查询交集一共有:" + searchHits.getTotalHits() + "条数据");
    }

    /*
         # 对数字进行范围查询(price在2000~3000的数据)
            GET goods/_search
            {
              "query": {
                "range": {
                  "price": {
                    "gte": 2000,
                    "lte": 2500
                  }
                }
              }
            }
     */
    @Test
    public void testRangeQuery() {
        //1. 创建查询条件构造器对象:用于查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件
        searchQueryBuilder.withQuery(QueryBuilders.rangeQuery("price").gte(2000).lte(2500));

        //3. 生成查询对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 根据查询条件对象,查询结果
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //5. 查询数据条数
        System.out.println("price在2000~2500的数据一共有:" + searchHits.getTotalHits() + "条数据");

    }

    /*
        # 模糊查询
        GET goods/_search
        {
          "query": {
            "wildcard": {
              "title": {
                "value": "华*"
              }
            }
          }
        }
     */
    @Test
    public void testWildcardQuery() {
        //1. 创建查询条件构造器对象:用于查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件
        searchQueryBuilder.withQuery(QueryBuilders.wildcardQuery("title", "华*"));

        //3. 生成查询条件对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 根据查询对象查询结果
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //5. 查询数据条数
        System.out.println("模糊查询(其中词条以华开头的)有:" + searchHits.getTotalHits() + "条数据");
    }

    /*
     * 分页查询+倒序查询
         # 分页降序查询(50条每页,以price降序)
            GET goods/_search
            {
              "query": {
                "match_all": {}
              },
              "from": 0,
              "size": 50,
              "sort": [
                {
                  "price": {
                    "order": "desc"
                  }
                }
              ]
            }
     */
    @Test
    public void testPageAndSort() {
        //1. 创建查询条件构造器对象:用于查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件
        //查询所有
        searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());

        //分页
        int page = 1;
        int pageSize = 10;
        searchQueryBuilder.withPageable(PageRequest.of(page - 1, pageSize));

        searchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));

        //3. 生成查询条件对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 根据查询对象查询结果
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //5. 查询数据条数
        System.out.println("模糊查询(其中词条以华开头的)有:" + searchHits.getTotalHits() + "条数据");

        List<GoodsDocument> list = new ArrayList<>();
        for (SearchHit<GoodsDocument> searchHit : searchHits) {
            GoodsDocument goodsDocument = searchHit.getContent();
            list.add(goodsDocument);
        }
        System.out.println("当前页有" + list.size() + "条数据");
    }

    /*
         # 高亮查询
            GET goods/_search
            {
              "query": {
                "match": {
                  "title": "华为手机"
                }
              },
              "highlight": {
                "fields": {
                  "title": {
                    "pre_tags": "",
                    "post_tags": ""
                  }
                }
              }
            }
     */
    @Test
    public void testHighLight() {
        //1. 创建查询条件构造器对象:用于查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件
        //查询所有
        searchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", "华为手机"));

        //高亮设置
        HighlightBuilder.Field field = new HighlightBuilder.Field("title");
        field.preTags("");
        field.postTags("");

        //注入高亮条件
        searchQueryBuilder.withHighlightFields(field);

        //3. 生成查询条件对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 查询
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        List<GoodsDocument> list = new ArrayList<>();

        for (SearchHit<GoodsDocument> searchHit : searchHits) {
            GoodsDocument goodsDocument = searchHit.getContent();

            //取出高亮
            List<String> titleList = searchHit.getHighlightFields().get("title");
            //判断titleList是否为空,不为空则替换原有的title
            if (titleList != null) {
                goodsDocument.setTitle(titleList.get(0));
            }

            list.add(goodsDocument);
        }

        list.forEach(System.out::println);
    }

    /*
        # 聚合查询
            GET goods/_search
            {
              "aggs": {
                "priceAvg": {
                  "avg": {
                    "field": "price"
                  }
                }
              }
            }
     */
    @Test
    public void testAggreationQuery() {
        //1. 创建查询条件构造器对象
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //2. 注入条件-->查询平均价格
        queryBuilder.addAggregation(AggregationBuilders.avg("priceAvg").field("price"));

        //3. 生成查询条件对象
        NativeSearchQuery searchQuery = queryBuilder.build();

        //4. 查询
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        Aggregations aggregations = searchHits.getAggregations();
        Avg avg = aggregations.get("priceAvg");

        System.out.println("聚合查询求平均分:" + avg.getValue());

    }

    /*
     * 查询最贵的华为
            GET goods/_search
            {
              "query": {
                "match": {
                  "title": "华为"
                }
              }
              , "aggs": {
                "max_price": {
                  "max": {
                    "field": "price"
                  }
                }
              }
            }
     */
    @Test
    public void testPriceMax(){
        //1. 创建查询构造器对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 注入查询条件---->查询条件
        searchQueryBuilder.withQuery(QueryBuilders.matchQuery("title" , "华为")).addAggregation(AggregationBuilders.max("max_price").field("price"));

        //3. 生成查询对象
        NativeSearchQuery searchQuery = searchQueryBuilder.build();

        //4. 查询
        SearchHits<GoodsDocument> searchHits = restTemplate.search(searchQuery, GoodsDocument.class);

        //5. 取出结果
        List<GoodsDocument> list = new ArrayList<>();
        for (SearchHit<GoodsDocument> searchHit : searchHits) {
            GoodsDocument goodsDocument = searchHit.getContent();

            list.add(goodsDocument);
        }

        Aggregations aggregations = searchHits.getAggregations();
        Max max = aggregations.get("max_price");

        System.out.println(max.getValue());

        list.forEach(System.out::println);
    }

}

4. 子模块springboot-resthighlevelclient

4.1 application.yaml

spring:
  elasticsearch:
    rest:
      uris: 192.168.153.133:9200

4.2 service层

package com.qq.es.service.impl;

import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 黔程似景
 * @description 使用RestHighLevelClient进行es相关的增删改查
 * @date 2023/6/17 12:07
 * @blame 黔程似景
 **/
@Service
public class RestHighLevelService {

    @Autowired
    private RestHighLevelClient client;

    /**
     * 创建索引
     * @param index 索引名称
     */
    public boolean createIndex(String index , String source) {
        boolean result = false;

        //1.创建添加索引库请求,指定索引库名称
        CreateIndexRequest indexRequest = new CreateIndexRequest(index);
        indexRequest.mapping(source , XContentType.JSON);
        try {
            //2.执行操作,获取返回值
            CreateIndexResponse createIndexResponse = client.indices().create(indexRequest, RequestOptions.DEFAULT);
            //3.创建结果
            result = createIndexResponse.isAcknowledged();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 添加文档
     *
     * @param index 索引名
     * @param data  文档内容
     * @return
     */
    public String addOrUpdateDoc(String index, String id, Map<String, Object> data) {
        //1.创建添加文档的请求,设置索引库名称,数据,是否有id
        IndexRequest request = new IndexRequest(index);
        if (id != null){
            request.id(id);
        }
        request.source(data);

        //2.执行请求,获取响应
        try {
            IndexResponse response = client.index(request, RequestOptions.DEFAULT);

            return response.getId();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除文档
     *
     * @param index 索引名
     * @param id    id
     * @return 文档id
     */
    public String deleteDoc(String index, String id) {
        //1.创建请求对象
        DeleteRequest request = new DeleteRequest("itheima").id("1");

        //2.执行请求,获取响应
        try {
            DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
            return response.getId();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //3.输出结果
        return null;
    }

    /**
     * 删除索引
     *
     * @param index 索引名称
     */
    public boolean deleteIndex(String index) {
        boolean result = false;

        DeleteIndexRequest indexRequest = new DeleteIndexRequest(index);
        try {
            AcknowledgedResponse delete = client.indices().delete(indexRequest, RequestOptions.DEFAULT);
            result = delete.isAcknowledged();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 指定索引进行全查询
     */
    public List<Map<String, Object>> matchAllQuery(String index , int page , int size) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.matchAllQuery()).from((page-1)*size).size(size);

        request.source(builder);
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 对指定的字段进行条件查询,其中对查询条件进行分词之后查询【取并集】
     * @param index 索引
     * @param page 当前页码
     * @param size 页大小
     * @param field 查询字段
     * @param value 查询条件
     * @param operator 是取查询条件进行分词之后查询条间的并集还是交集【0:代表并集,1:代表交集】
     */
    public List<Map<String , Object>> matchQuery(String index, int page, int size, String field, Object value, int operator) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(field, value);
        if (operator == 1){
            matchQuery.operator(Operator.AND);
        }
        builder.query(matchQuery).from((page-1)*size).size(size);

        request.source(builder);
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 精准查询
     *
     * @param index 索引
     * @param page  当前页
     * @param size  页大小
     * @param field  查询字段
     * @param value  字段查询条件
     */
    public List<Map<String, Object>> termQuery(String index, int page, int size , String field , Object value) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.termQuery(field,value)).from((page-1)*size).size(size);

        request.source(builder);

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 范围查询
     *
     * @param index 索引
     * @param page  当前页
     * @param size  页大小
     * @param field 查询字段
     * @param gte   最小值
     * @param lte   最大值
     */
    public List<Map<String, Object>> rangeQuery(String index, int page, int size, String field, Object gte, Object lte) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.rangeQuery(field).gte(gte).lte(lte)).from((page-1)*size).size(size);

        request.source(builder);

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 模糊查询   查询以“张“开头的则为”张*“
     *
     * @param index 索引
     * @param page  当前页
     * @param size  页大小
     * @param field 查询字段
     * @param value 条件
     */
    public List<Map<String, Object>> wildcardQuery(String index, int page, int size, String field, String value) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.wildcardQuery(field,value)).from((page-1)*size).size(size);

        request.source(builder);

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 降序排序
     *
     * @param index 索引
     * @param page  当前页
     * @param size  页大小
     * @param field 查询字段
     */
    public List<Map<String, Object>> sortQuery(String index, int page, int size, String field) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.matchAllQuery()).from((page-1)*size).size(size);

        builder.sort(field, SortOrder.DESC);

        request.source(builder);

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    public List<Map<String , Object>> boolQuery(String index, int page, int size) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest request = new SearchRequest(index);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must().add(QueryBuilders.matchQuery("title","华为手机"));
        boolQuery.must().add(QueryBuilders.rangeQuery("price").gte(2000D).lte(3000D));
        builder.query(boolQuery).from((page-1)*size).size(size);

        request.source(builder);
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> source = hit.getSourceAsMap();
                list.add(source);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 高亮显示某字段
     *
     * @param index 索引
     * @param page  当前页
     * @param size  页大小
     * @param field 查询字段
     * @param value 查询条件
     */
    public List<Map<String, Object>> highLightQuery(String index, int page, int size, String field ,String value) {
        List<Map<String, Object>> list = new ArrayList<>();

        SearchRequest searchRequest = new SearchRequest(index);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(field, value);
        searchSourceBuilder.query(termQueryBuilder).from((page-1)*size).size(size);

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("");
        highlightBuilder.postTags("");
        highlightBuilder.field(field);
        searchSourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();
            System.out.println("符合条件的总文档数量:" + hits.getTotalHits().value);
            hits.forEach(hit -> {

                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                String title = hit.getHighlightFields().get(field).getFragments()[0].toString();
                sourceAsMap.put("title" , title);
                list.add(sourceAsMap);
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

}

4.3 启动类

package com.qq.es;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author 黔程似景
 * @description 启动类
 * @date 2023/6/17 11:45
 * @blame 黔程似景
 **/
@SpringBootApplication
public class ApplicationStarter {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationStarter.class , args);
    }

}

4.4 测试类

package com.qq.es.test.service.impl;

import com.qq.es.service.RestHighLevelService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 黔程似景
 * @description
 * @date 2023/6/17 12:24
 * @blame 黔程似景
 **/
@SpringBootTest
@RunWith(SpringRunner.class)
public class RestHighLevelServiceImplTest {

    @Autowired
    private RestHighLevelService restHighLevelService;

    @Test
    public void test_addDoc() {
        Map<String, Object> data = new HashMap<>();
        data.put("name" , "qian黔景");
        data.put("age" , "20");
        String doc = restHighLevelService.addOrUpdateDoc("qianjing", "-geezogB5XfR_FCc1ea9", data);

        System.out.println(doc);
    }

    /**
     * 其实没有mapping也是可以生成文档的。
     * @throws IOException
     */
    @Test
    public void test_createMappingIndex() {
        String source = "{\n" +
                "    \"properties\": {\n" +
                "      \"name\":{\n" +
                "        \"type\": \"text\"\n" +
                "      },\n" +
                "      \"age\":{\n" +
                "        \"type\": \"integer\"\n" +
                "      }\n" +
                "    }\n" +
                "  }";
        boolean result = restHighLevelService.createIndex("qianjing", source);

        System.out.println(result);
    }

    @Test
    public void test_matchAll() {
        List<Map<String, Object>> goods = restHighLevelService.matchAllQuery("goods" , 1 , 20);

        goods.forEach(System.out::println);
    }

    @Test
    public void test_sortQuery() {
        List<Map<String, Object>> goods = restHighLevelService.sortQuery("goods" , 1 , 20 , "price");

        goods.forEach(System.out::println);
    }

    @Test
    public void testHighlight() {

        List<Map<String, Object>> list = restHighLevelService.highLightQuery("goods" , 1 , 20 , "title" , "联通");

        for (Map<String, Object> map : list) {
            System.out.println(map);
        }
    }

    @Test
    public void testBoolQuery() {
        List<Map<String, Object>> list = restHighLevelService.boolQuery("goods" , 1 , 20);
        for (Map<String, Object> map : list) {
            System.out.println(map);
        }
    }

}

你可能感兴趣的:(elasticsearch,spring,boot,搜索引擎,全文检索)