SpringBoot整合ES查询

springboot整个es有很多钟方法,比如TransportClient、RestClient、RestHighLevelClient、SpringData-Es、Elasticsearch-SQL等。

ElasticSearch 官方提供了 3 个 Client,具体如下:

  • org.elasticsearch.client.transport.TransportClient
  • org.elasticsearch.client.RestClient
  • org.elasticsearch.client.RestHighLevelClient

TransportClient 位于 Elasticsearch 包下,是 Elasticsearch 官方早期支持的 ElasticSearch Client,但是在 ElasticSearch 7.x 版本中已经标注为 Deprecated,并且将在 8.0 版本中移除,所以建议不使用 TransportClient 作为 ElasticSearch Client。
RestHighLevelClient 是 TransportClient 的直接替代者,也是 ElasticSearch 官方推荐和默认的 Client

准备数据

delete employees

PUT /employees/
{
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "gender": {
        "type": "keyword"
      },
      "job": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 50
          }
        }
      },
      "name": {
        "type": "keyword"
      },
      "salary": {
        "type": "integer"
      }
    }
  }
}

PUT /employees/_bulk
{ "index" : {  "_id" : "1" } }
{ "name" : "Emma","age":32,"job":"Product Manager","gender":"female","salary":35000 }
{ "index" : {  "_id" : "2" } }
{ "name" : "Underwood","age":41,"job":"Dev Manager","gender":"male","salary": 50000}
{ "index" : {  "_id" : "3" } }
{ "name" : "Tran","age":25,"job":"Web Designer","gender":"male","salary":18000 }
{ "index" : {  "_id" : "4" } }
{ "name" : "Rivera","age":26,"job":"Web Designer","gender":"female","salary": 22000}
{ "index" : {  "_id" : "5" } }
{ "name" : "Rose","age":25,"job":"QA","gender":"female","salary":18000 }
{ "index" : {  "_id" : "6" } }
{ "name" : "Lucy","age":31,"job":"QA","gender":"female","salary": 25000}
{ "index" : {  "_id" : "7" } }
{ "name" : "Byrd","age":27,"job":"QA","gender":"male","salary":20000 }
{ "index" : {  "_id" : "8" } }
{ "name" : "Foster","age":27,"job":"Java Programmer","gender":"male","salary": 20000}
{ "index" : {  "_id" : "9" } }
{ "name" : "Gregory","age":32,"job":"Java Programmer","gender":"male","salary":22000 }
{ "index" : {  "_id" : "10" } }
{ "name" : "Bryant","age":20,"job":"Java Programmer","gender":"male","salary": 9000}
{ "index" : {  "_id" : "11" } }
{ "name" : "Jenny","age":36,"job":"Java Programmer","gender":"female","salary":38000 }
{ "index" : {  "_id" : "12" } }
{ "name" : "Mcdonald","age":31,"job":"Java Programmer","gender":"male","salary": 32000}
{ "index" : {  "_id" : "13" } }
{ "name" : "Jonthna","age":30,"job":"Java Programmer","gender":"female","salary":30000 }
{ "index" : {  "_id" : "14" } }
{ "name" : "Marshall","age":32,"job":"Javascript Programmer","gender":"male","salary": 25000}
{ "index" : {  "_id" : "15" } }
{ "name" : "King","age":33,"job":"Java Programmer","gender":"male","salary":28000 }
{ "index" : {  "_id" : "16" } }
{ "name" : "Mccarthy","age":21,"job":"Javascript Programmer","gender":"male","salary": 16000}
{ "index" : {  "_id" : "17" } }
{ "name" : "Goodwin","age":25,"job":"Javascript Programmer","gender":"male","salary": 16000}
{ "index" : {  "_id" : "18" } }
{ "name" : "Catherine","age":29,"job":"Javascript Programmer","gender":"female","salary": 20000}
{ "index" : {  "_id" : "19" } }
{ "name" : "Boone","age":30,"job":"DBA","gender":"male","salary": 30000}
{ "index" : {  "_id" : "20" } }
{ "name" : "Kathy","age":29,"job":"DBA","gender":"female","salary": 20000}

引入依赖

可以复制下边的依赖贴入POM文件,还可以在阿里云的脚手架上勾选,然后下载生成的工程

 <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.15</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.tenic.springbootes.SpringbootEsApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

修改配置文件

# 应用名称
spring.application.name=springboot-es

elasticsearch.host=x.x.x.x
elasticsearch.port=9200
elasticsearch.username=
elasticsearch.password=

目录结构

image.png

创建配置类,配置ES相关信息,并创建RestHighLevelClient

@Configuration
public class ElasticsearchConfig {

    @Value("${elasticsearch.host}")
    private String host;

    @Value("${elasticsearch.port}")
    private int port;

    @Value("${elasticsearch.username}")
    private String userName;

    @Value("${elasticsearch.password}")
    private String password;

    @Bean(destroyMethod = "close")
    public RestHighLevelClient restClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(userName, password));

        RestClientBuilder builder = RestClient.builder(new HttpHost(host, port))
                .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
        RestHighLevelClient client = new RestHighLevelClient(builder);
        return client;

    }
}

创建映射实体

@Data
public class Employees {

    private String name;

    private Integer age;

    private String gender;

    private String job;

    private Integer salary;
}

配置工具类

public interface Constant {
    String EMPLOYEES_INDEX = "employees";
}

创建测试类

@SpringBootTest
@RunWith(SpringRunner.class)
class SpringbootEsApplicationTests {
    @Test
    void contextLoads() {}
}

继承测试类,本地CRUD测试一下

public class SpringbootEsApplicationDemo1  extends SpringbootEsApplicationTests{

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 查询索引employees
     * @throws IOException
     */
    @Test
    public void test1() throws IOException {
        QueryBuilder queryBuilder = new MatchAllQueryBuilder();
        SearchResponse response = search(queryBuilder);
        printResponse(response);
    }

    /**
     * 插入文档
     * @throws IOException
     */
    @Test
    public void test2() throws IOException {
        Employees employees = new Employees("zhangsan",44,"male","CTO",3300);
        IndexRequest indexRequest = new IndexRequest(EMPLOYEES_INDEX);
        indexRequest.id("21").source(JSONObject.toJSONString(employees),XContentType.JSON);
        IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println("创建状态:"+indexResponse.status());
        System.out.println(indexResponse);
    }

    /**
     * 更新文档
     * @throws IOException
     */
    @Test
    public void test3() throws IOException {
        UpdateRequest updateRequest = new UpdateRequest(EMPLOYEES_INDEX,"21");
        Employees employee = new Employees();
        employee.setName("wangwu");
        updateRequest.doc(JSONObject.toJSONString(employee),XContentType.JSON);
        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println("更新状态:"+update.status());
        System.out.println(update);
    }

    /**
     * 删除文档
     * @throws IOException
     */
    @Test
    public void test4() throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest(EMPLOYEES_INDEX,"21");
        DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println("删除状态:"+deleteResponse.status());
        System.out.println(deleteResponse);
    }

    /**
     * 高亮查询
     * @throws IOException
     */

    @Test
    public void test5() throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(EMPLOYEES_INDEX);
        // term 查询
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder query = new TermQueryBuilder("job","programmer");
        sourceBuilder.query(query);
        // 高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.field("*");
        sourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("查询状态:"+searchResponse.status());
        System.out.println("查询总条数:"+searchResponse.getHits().getTotalHits());
        printResponse(searchResponse);
    }

	/**
     * 查询索引
	 */
    private SearchResponse search(QueryBuilder query) throws IOException {
        SearchRequest searchSource = new SearchRequest();
        searchSource.indices(EMPLOYEES_INDEX);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(query);

        searchSource.source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(searchSource, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        System.out.println("查询状态:"+response.status());
        System.out.println("查询总条数:"+hits.getTotalHits());
        return response;
    }

    /**
     * 打印结果,并转换成实体对象
     */
    private void printResponse(SearchResponse response) {
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits.getHits()) {
            Employees employees = JSONObject.parseObject(hit.getSourceAsString(), Employees.class);
            System.out.println(employees);
        }
    }
}

分页查询,search after,scroll api查询

public class SpringbootEsApplicationDemo2 extends SpringbootEsApplicationTests{

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    /**
     * FROM/SIZE 分页查询,from:从指定行开始,size:需要查询页的条数
     * ES最大查询是10000条数据,所以要FROM+SIZE<=10000
     * @throws IOException
     */
    @Test
    public void test1() throws IOException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = new MatchAllQueryBuilder();
        sourceBuilder.query(queryBuilder);
        sourceBuilder.from(2);
        sourceBuilder.size(5);

        processESCmd(sourceBuilder);
    }

    /**
     * search after 深度分页查询数据
     * @throws IOException
     */
    @Test
    public void test2() throws IOException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = new MatchAllQueryBuilder();
        sourceBuilder.query(queryBuilder);
        sourceBuilder.size(19);
        sourceBuilder.sort("age", SortOrder.DESC);
        sourceBuilder.sort("_id",SortOrder.ASC);
        SearchResponse searchResponse = processESCmd(sourceBuilder);
        while(searchResponse.getHits().getHits().length>0) {
            SearchHit[] hits = searchResponse.getHits().getHits();
            SearchHit hit = hits[hits.length - 1];
            sourceBuilder.searchAfter(hit.getSortValues());
            searchResponse = processESCmd(sourceBuilder);
        }
    }

      /**
     * scroll api 查询
     * 基于快照查询,此时如果有新数据插入索引,该查询不会查到
     * 其中scrollRequest.scroll("1m");中设置的是scroll请求的上下文的存活时间
     * @throws IOException
     */
    @Test
    public void test3() throws IOException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = new MatchAllQueryBuilder();
        sourceBuilder.query(queryBuilder);
        sourceBuilder.size(5);
        SearchRequest searchRequest = new SearchRequest(EMPLOYEES_INDEX);
        searchRequest.scroll("1m");
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        while(search.getHits().getHits().length>0){
            for (SearchHit hit : search.getHits()) {
                System.out.println("ID:"+hit.getId()+"--"+ JSONObject.parseObject(hit.getSourceAsString(), Employees.class));
            }
            String scrollId = search.getScrollId();
            SearchScrollRequest scrollRequest = new SearchScrollRequest();
            scrollRequest.scrollId(scrollId);
            scrollRequest.scroll("1m");
            search = restHighLevelClient.scroll(scrollRequest,RequestOptions.DEFAULT);
        }

    }

    private SearchResponse processESCmd(SearchSourceBuilder sourceBuilder) throws IOException {
        SearchRequest searchRequest = new SearchRequest(EMPLOYEES_INDEX);
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("查询状态:"+search.status());
        System.out.println("查询条数:"+search.getHits().getHits().length);
        for (SearchHit hit : search.getHits()) {
            System.out.println("ID:"+hit.getId()+"--"+ JSONObject.parseObject(hit.getSourceAsString(), Employees.class));
        }
        return search;
    }
}
posted @ 2022-10-16 11:54  Tenic  阅读(3298)  评论(0编辑  收藏  举报