Spring Boot 集成 Elasticsearch

原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/15229906.html

Project Directory

Maven Dependency

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>org.fool.es</groupId>
    <artifactId>hello-spring-data-es</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
View Code

application.properties

server.port=8080

logging.level.org.fool.es=debug

elasticsearch.host=127.0.0.1
elasticsearch.port=9200

SRC

Application.java

package org.fool.es;

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

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

ElasticsearchConfig.java

package org.fool.es.config;

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;

@ConfigurationProperties(prefix = "elasticsearch")
@Configuration
@Data
@EqualsAndHashCode(callSuper = true)
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
    private String host;
    private Integer port;

    @Override
    public RestHighLevelClient elasticsearchClient() {
        return new RestHighLevelClient(RestClient.builder(new HttpHost(host, port)));
    }
}

使用 ElasticsearchRepository 进行通用的 CRUD

Product.java

package org.fool.es.index;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
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;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "product", shards = 1, replicas = 1)
public class Product {
    @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.Double)
    private Double price;
    @Field(type = FieldType.Keyword, index = false)
    private String imageUrl;
}

ProductDAO.java

package org.fool.es.dao;

import org.fool.es.index.Product;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ProductDAO extends ElasticsearchRepository<Product, Long> {
    List<Product> findByTitle(String title);

    List<Product> findByTitle(String title, Pageable pageable);

    List<Product> findByTitleAndCategory(String title, String category);

    List<Product> findByTitleOrCategory(String title, String category);

}

SpringDataESTest.java

package org.fool.es.test;

import org.fool.es.dao.ProductDAO;
import org.fool.es.index.Product;
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.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;

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

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

    @Autowired
    private ProductDAO productDAO;

    ......
}

insert

@Test
public void testInsert() {
    Product product = new Product();
    product.setId(1001L);
    product.setTitle("iPhone X");
    product.setCategory("mobile");
    product.setPrice(6999.0);
    product.setImageUrl("http://www.apple.com/iPhone.jpg");
    productDAO.save(product);
}

update

@Test
public void testUpdate() {
    Product product = new Product();
    product.setId(1001L);
    product.setTitle("iPhone X Max");
    product.setCategory("mobile");
    product.setPrice(8999.0);
    product.setImageUrl("http://www.apple.com/iPhone.jpg");
    productDAO.save(product);
}

delete

@Test
public void testDelete() {
    Product product = new Product();
    product.setId(1001L);
    productDAO.delete(product);
}

batchInsert

@Test
public void testBatchInsert() {
    List<Product> productList = new ArrayList<>();

    for (int i = 0; i < 10; i++) {
        Product product = new Product();
        product.setId((long) i);
        product.setTitle("iPhone " + i);
        product.setCategory("mobile");
        product.setPrice(6999.0 + i);
        product.setImageUrl("http://www.apple.com/iPhone.jpg");
        productList.add(product);
    }

    productDAO.saveAll(productList);
}

findById

@Test
public void testFindById() {
    productDAO.findById(1001L).ifPresent(System.out::println);
}

findAll

@Test
public void testFindAll() {
    productDAO.findAll().forEach(System.out::println);
}

findByPageable

@Test
public void findByPageable() {
    Sort sort = Sort.by(Sort.Direction.DESC, "id");
    int currentPage = 0;
    int pageSize = 5;

    PageRequest pageRequest = PageRequest.of(currentPage, pageSize, sort);

    Page<Product> results = productDAO.findAll(pageRequest);

    System.out.println(results.getTotalPages());
    System.out.println(results.getSize());
    System.out.println(results.getNumber());

    results.getContent().forEach(System.out::println);
}

findByTitle

@Test
public void testFindByTitle() {
    productDAO.findByTitle("iPhone 8").forEach(System.out::println);
}

findByTitleWithPagination

@Test
public void testFindByTitleWithPagination() {
    productDAO.findByTitle("iPhone", PageRequest.of(0, 5)).forEach(System.out::println);
}

findByTitleOrCategory

@Test
public void testFindByTitleOrCategory() {
    productDAO.findByTitleOrCategory("iPhone", "mobile").forEach(System.out::println);
}

findByTitleAndCategory

@Test
public void testFindByTitleAndCategory() {
    productDAO.findByTitleAndCategory("iPhone", "pad").forEach(System.out::println);
}

使用 NativeSearchQuery 进行复杂查询

User.java

package org.fool.es.index;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
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;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "user", shards = 1, replicas = 1)
public class User {
    @Id
    private Long id;
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String name;
    @Field(type = FieldType.Keyword)
    private String sex;
    @Field(type = FieldType.Integer)
    private Integer age;
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String address;
}

UserDAO.java

package org.fool.es.dao;

import org.fool.es.index.User;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserDAO extends ElasticsearchRepository<User, Long> {

}

SpringESNativeSearchQueryTest.java

package org.fool.es.test;

import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.fool.es.dao.UserDAO;
import org.fool.es.index.User;
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.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.data.elasticsearch.core.query.SourceFilter;
import org.springframework.test.context.junit4.SpringRunner;

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

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

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Test
    public void testBatchInsert() throws Exception {
        List<User> recordList = new ArrayList<>();
        recordList.add(new User(1001L, "caocao", "male", 10, "shanghai"));
        recordList.add(new User(1002L, "liubei", "male", 20, "beijing"));
        recordList.add(new User(1003L, "sunquan", "male", 30, "shenzhen"));
        recordList.add(new User(1004L, "guanyu", "male", 40, "guangzhou"));
        recordList.add(new User(1005L, "zhangfei", "male", 40, "shanghai"));
        recordList.add(new User(1006L, "zhaoyun", "male", 50, "beijing"));
        recordList.add(new User(1007L, "caocao2", "female", 50, "chengdu"));

        userDAO.saveAll(recordList);
    }

    @Test
    public void testDelete() {
        userDAO.deleteAll();
    }

    ......

}

Note:

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

queryAll

@Test
public void testQueryAll() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(new MatchAllQueryBuilder())
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryString

@Test
public void testQueryString() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            // query field address
            .withQuery(QueryBuilders.queryStringQuery("shanghai").defaultField("address"))
            // query all field
            //.withQuery(QueryBuilders.queryStringQuery("shanghai"))
            // query field name, address
            //.withQuery(QueryBuilders.queryStringQuery("shanghai").field("name").field("address"))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryTerm

@Test
public void testQueryTerm() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.termQuery("name", "caocao"))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryPagination

@Test
public void testQueryPagination() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchAllQuery())
            .withPageable(PageRequest.of(0, 5))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

querySort

@Test
public void testQuerySort() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchAllQuery())
            .withPageable(PageRequest.of(0, 5))
            .withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryFilter

@Test
public void testQueryFilter() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchAllQuery())
            .withPageable(PageRequest.of(0, 5))
            .withSourceFilter(new SourceFilter() {
                @Override
                public String[] getIncludes() {
                    return new String[]{"name"};
                }

                @Override
                public String[] getExcludes() {
                    return new String[]{};
                }
            }).build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryBool

@Test
public void testQueryBool() {
    // or
    //NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
    //        .withQuery(QueryBuilders.boolQuery()
    //                .should(QueryBuilders.termQuery("age", 30))
    //                .should(QueryBuilders.termQuery("sex", "female")))
    //        .build();

    // and
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("age", 30))
                    .must(QueryBuilders.termQuery("sex", "male")))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryRange

@Test
public void testQueryRange() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.rangeQuery("age").gte(30).lte(50))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryFuzzy

@Test
public void testQueryFuzzy() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.fuzzyQuery("name", "caocao").fuzziness(Fuzziness.ONE))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
    }
}

queryHighlight

@Test
public void testQueryHighlight() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.termQuery("name", "caocao"))
            .withHighlightFields(new HighlightBuilder.Field("name").preTags("<font color='red'>").postTags("</font>"))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);
    List<SearchHit<User>> list = searchHits.getSearchHits();
    for (SearchHit<User> record : list) {
        System.out.println(record.getContent());
        System.out.println(record.getHighlightFields());
    }
}

queryAggregation

@Test
public void testQueryAggregation() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .addAggregation(AggregationBuilders.max("maxAge").field("age"))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);

    Aggregations aggregations = searchHits.getAggregations();
    assert aggregations != null;
    ParsedMax terms = aggregations.get("maxAge");
    System.out.println(terms.getValue());
}

queryGroup

@Test
public void testQueryGroup() {
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            .addAggregation(AggregationBuilders.terms("ageGroup").field("age"))
            .build();

    SearchHits<User> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, User.class);

    long count = searchHits.getTotalHits();
    System.out.println(count);

    Aggregations aggregations = searchHits.getAggregations();
    assert aggregations != null;
    ParsedLongTerms terms = aggregations.get("ageGroup");
    List<? extends Terms.Bucket> buckets = terms.getBuckets();
    for (Terms.Bucket bucket : buckets) {
        System.out.println(bucket.getKey() + ":" + bucket.getDocCount());
    }
}

Reference

https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.repositories


欢迎点赞关注和收藏

强者自救 圣者渡人
原文地址:https://www.cnblogs.com/agilestyle/p/15229906.html