Spring Boot 配置 ElasticSearch7

Elasticsearch 版本: 7.6.2.

Spring boot版本: 2.3.0.RELEASE

 

快速跳转

引入POM依赖

配置yml

创建定义索引的实体类

创建Setting文件

利用xxxRequest,xxxReponseI进行增删改查

利用Spring Data 提供的接口进行增删改查

利用Spring data JPA,根据属性名进行组合检索

自定义检索

 

引入POM依赖

方式1:

Spring boot 项目创建时选择NoSQL -- Spring dataElasticSearch 

 

方式2 : 在POM处引入依赖

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

 

由于本人没有7.17.4 版本对应的ik分词器和拼音分词器,所以降了spring boot的版本为 2.3.0.RELEASE, 对应的ES版本降为7.6.2

 

配置yml

server:
  port: 8888
spring:
  elasticsearch:
    uris: http://localhost:9200
    username:
    password:

 

创建定义索引的实体类

@Data
@Document(indexName = "user")
@Setting(settingPath = "/setting/pinyin.analyzer.json")
public class User {

    @Field
    private String id;

    @Field(type = FieldType.Text,name = "name")
    private String name;

    @Field(name = "desc",type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String desc;

    @Field(name = "age",type = FieldType.Integer)
    private Integer age;

    @Field(name = "phone",type = FieldType.Keyword)
    private String phone;

    @Field(name = "like", type = FieldType.Text, analyzer = "pinyin_analyzer_ik_max", searchAnalyzer = "ik_max_word")
    private String like;
}

@Document注解用来定义索引名称、索引分片、索引副本,是否自动创建索引等,这个只需定义一个索引名称,其余均默认即可。

@Setting注解可以引入自定义的index.setting, 如果有自定义的分词器,可以通过此注解引入,如果没有,这个注解可忽略。

@Field注解用来定义字段信息,需重点关注的为name, type, analyzer, search_analyzer这四项。

 

创建Setting文件

如果有自定义的setting内容,则需在resource文件夹下存放setting.json, 即@Setting注解对应的路径

 

利用xxxRequestApi + xxxResponseApi进行增删改查

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
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.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
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.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
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.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import java.util.List;

@SpringBootTest
@Slf4j
public class OriginalApiTest {

    @Test
    @SneakyThrows
    void originalApiTest() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .withBasicAuth("elastic_name", "elastic_password")
                .build();
        //连接客户端
        RestHighLevelClient esClient = RestClients.create(clientConfiguration).rest();

        String indexName = "client-test";

        //创建索引
        createIndex(esClient,indexName);

        //查询索引
        getIndex(esClient,indexName);
        //文档操作
        documentOptions(esClient,indexName);
        //文档批量操作
        documentBatchOptions(esClient,indexName);
        //组合查询
        complexQuery(esClient,indexName);
        //删除索引
        deleteIndex(esClient,indexName);
        //关闭索引
        esClient.close();
    }

    private static void complexQuery(RestHighLevelClient esClient, String indexName) throws Exception {

        //全量查询
        queryAll(esClient,indexName);

        //条件查询
        queryCondition(esClient,indexName);

        //分页查询、排序、过滤、高亮
        queryPageAndSort(esClient,indexName);

        //组合查询
        queryBool(esClient,indexName);

        //范围查询
        queryRange(esClient,indexName);

        //聚合查询--最大值
        queryAggMax(esClient,indexName);

        //聚合查询--分组
        queryAggTermGroup(esClient,indexName);

    }

    private static void queryAggTermGroup(RestHighLevelClient esClient, String indexName)  throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        AggregationBuilder aggregationBuilder = AggregationBuilders.terms("ageGroup").field("age");
        sourceBuilder.aggregation(aggregationBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        ParsedLongTerms ageGroup = (ParsedLongTerms)searchResponse.getAggregations().getAsMap().get("ageGroup");
        List<? extends Terms.Bucket> buckets = ageGroup.getBuckets();
        for (Terms.Bucket item : buckets) {
            log.info("age:{}, count:{}",item.getKey(),item.getDocCount());
        }
    }



    private static void queryAggMax(RestHighLevelClient esClient, String indexName)  throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        AggregationBuilder aggregationBuilder = AggregationBuilders.max("maxAge").field("age");
        sourceBuilder.aggregation(aggregationBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        List<Aggregation> aggregations = searchResponse.getAggregations().asList();
        for (Aggregation agg : aggregations) {
            ParsedMax ageMax = (ParsedMax)agg;
            log.info("ageMax:{}",ageMax.getValue());
        }
    }


    private static void queryRange(RestHighLevelClient esClient, String indexName) throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gt(10).lt(19);
        sourceBuilder.query(rangeQueryBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        print("queryRange",searchResponse.getHits());
    }

    private static void queryBool(RestHighLevelClient esClient, String indexName) throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("age","30"));//should\must\must_not
        boolQueryBuilder.must(QueryBuilders.matchQuery("sex","男"));
        sourceBuilder.query(boolQueryBuilder);

        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        print("queryBool",searchResponse.getHits());
    }

    private static void queryPageAndSort(RestHighLevelClient esClient, String indexName) throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        String[] ec = new String[]{"sex"};
        String[] ic = new String[]{"name","age"};
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())
                .from(0).size(5)
                .fetchSource(ic,ec)
                .highlighter(new HighlightBuilder().field("name"))
                .sort("age", SortOrder.DESC);
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        print("queryPageAndSort",searchResponse.getHits());
    }

    private static void queryCondition(RestHighLevelClient esClient, String indexName) throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);
        searchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("age",18)));
        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        print("queryCondition",searchResponse.getHits());
    }

    private static void queryAll(RestHighLevelClient esClient, String indexName) throws Exception{
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);
        searchRequest.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        print("queryAll", searchResponse.getHits());
    }

    private static void print(String desc, SearchHits hits) {
        for (SearchHit hit : hits) {
            log.info(desc +":{}" , hit.getSourceAsString());
        }
    }

    private void documentBatchOptions(RestHighLevelClient esClient, String indexName) throws Exception{
        //批量新增
        bulkAdd(esClient,indexName);
        //批量删除
        bulkDelete(esClient,indexName);
    }

    private void bulkDelete(RestHighLevelClient esClient, String indexName) throws Exception{
        BulkRequest bulkDeleteRequest = new BulkRequest();
        bulkDeleteRequest.add(new DeleteRequest(indexName).id("1001"));
        bulkDeleteRequest.add(new DeleteRequest(indexName).id("1002"));
        bulkDeleteRequest.add(new DeleteRequest(indexName).id("1003"));
        BulkResponse deleteResponse = esClient.bulk(bulkDeleteRequest, RequestOptions.DEFAULT);
        log.info("批量删除状态为:{}",deleteResponse.status());
        //查询
        queryAll(esClient,indexName);
    }

    private void bulkAdd(RestHighLevelClient esClient, String indexName) throws Exception{
        //批量新增
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.add(new IndexRequest(indexName).id("1001").source(XContentType.JSON,"name","张三","age",30));
        bulkRequest.add(new IndexRequest(indexName).id("1002").source(XContentType.JSON,"name","李四","age",40));
        bulkRequest.add(new IndexRequest(indexName).id("1003").source(XContentType.JSON,"name","王五","age",50));
        bulkRequest.add(new IndexRequest(indexName).id("1004").source(XContentType.JSON,"name","张龙","age",18));
        bulkRequest.add(new IndexRequest(indexName).id("1005").source(XContentType.JSON,"name","赵虎","age",19));
        bulkRequest.add(new IndexRequest(indexName).id("1006").source(XContentType.JSON,"name","王朝","age",18));
        bulkRequest.add(new IndexRequest(indexName).id("1007").source(XContentType.JSON,"name","马汉","age",19));

        BulkResponse bulkResponse = esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        log.info("批量添加结果:{}",bulkResponse.status());

        //查询
       queryAll(esClient,indexName);
    }

    private void documentOptions(RestHighLevelClient esClient, String indexName) throws Exception{
        User user = new User();
        user.setId(1001);
        user.setName("唐僧");
        user.setAge(18);
        user.setDesc("三藏,御弟,金蝉子");
        user.setLike("西天取经,讲经说法");
        user.setPhone("13453345678");

        insertDoc(esClient,indexName,user);
        user.setName("唐僧2");
        updateDoc(esClient,indexName,user);
        searchDoc(esClient, indexName, user.getId().toString());
        deleteDoc(esClient,indexName,user.getId().toString());
        searchDoc(esClient, indexName, user.getId().toString());
    }

    private void searchDoc(RestHighLevelClient esClient, String indexName, String id) throws Exception{
        //查询
        GetRequest getRequest = new GetRequest();
        getRequest.index(indexName).id(id);
        GetResponse getResponse = esClient.get(getRequest, RequestOptions.DEFAULT);
        log.info("查询id为{}的数据,结果为:{}",id,getResponse.getSourceAsString());
    }

    private void deleteDoc(RestHighLevelClient esClient, String indexName, String id) throws Exception{
        //删除
        DeleteRequest deleteRequest = new DeleteRequest();
        deleteRequest.index(indexName).id(id);
        DeleteResponse delete = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println(delete.toString());
    }

    private void updateDoc(RestHighLevelClient esClient, String indexName, User user) throws Exception{
        //更新
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index(indexName).id(user.getId().toString());
        updateRequest.doc(XContentType.JSON,"sex","女");
        UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT);
        log.info("更新文档:{}", updateResponse.getResult());
    }

    private void insertDoc(RestHighLevelClient esClient, String indexName, User user) throws Exception{
        //新增
        IndexRequest indexRequest = new IndexRequest();
        indexRequest.index(indexName).id(user.getId().toString());

        //向ES插入数据需转换成json格式
        ObjectMapper mapper = new ObjectMapper();
        String source = mapper.writeValueAsString(user);
        indexRequest.source(source, XContentType.JSON);

        IndexResponse indexReponse = esClient.index(indexRequest, RequestOptions.DEFAULT);
        log.info("新增文档:{}",indexReponse.getResult());

    }

    private void deleteIndex(RestHighLevelClient esClient, String indexName) throws Exception{
        //删除索引
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
        AcknowledgedResponse deleteRespose = esClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        log.info("删除索引状态:{}" , deleteRespose);
    }

    private void getIndex(RestHighLevelClient esClient, String indexName) throws Exception{
        //查询索引
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        GetIndexResponse getIndexResponse = esClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);

        log.info("索引别名:{}",getIndexResponse.getAliases());
        log.info("索引Mapping:{}",getIndexResponse.getMappings());
        log.info("索引Setting:{}",getIndexResponse.getSettings());
    }

    private void createIndex(RestHighLevelClient esClient,String indexName) throws Exception{
        //创建索引
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        boolean exists = esClient.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
        if (!exists) {
            CreateIndexResponse response = esClient.indices().create(request, RequestOptions.DEFAULT);

            //响应状态
            boolean acknowledged = response.isAcknowledged();
            log.info("创建索引状态:{}" , acknowledged);
        } else {
            log.info("索引{}已存在",indexName);
        }

    }
}
RequestAndResponseApiTest

 

利用Spring Data 提供的接口进行增删改查

 一个比较草率的图

 

 

PagingAndSorting中,已经为我们定义好了两个Find方法

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {

    /**
     * Returns all entities sorted by the given options.
     *
     * @param sort
     * @return all entities sorted by the given options
     */
    Iterable<T> findAll(Sort sort);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     *
     * @param pageable
     * @return a page of entities
     */
    Page<T> findAll(Pageable pageable);
}
PagingAndSortingRepository

在CurdRepository中,为我们定义了一批基础的增删改查方法

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

    /**
     * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
     * entity instance completely.
     *
     * @param entity must not be {@literal null}.
     * @return the saved entity; will never be {@literal null}.
     * @throws IllegalArgumentException in case the given {@literal entity} is {@literal null}.
     */
    <S extends T> S save(S entity);

    /**
     * Saves all given entities.
     *
     * @param entities must not be {@literal null} nor must it contain {@literal null}.
     * @return the saved entities; will never be {@literal null}. The returned {@literal Iterable} will have the same size
     *         as the {@literal Iterable} passed as an argument.
     * @throws IllegalArgumentException in case the given {@link Iterable entities} or one of its entities is
     *           {@literal null}.
     */
    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    /**
     * Retrieves an entity by its id.
     *
     * @param id must not be {@literal null}.
     * @return the entity with the given id or {@literal Optional#empty()} if none found.
     * @throws IllegalArgumentException if {@literal id} is {@literal null}.
     */
    Optional<T> findById(ID id);

    /**
     * Returns whether an entity with the given id exists.
     *
     * @param id must not be {@literal null}.
     * @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
     * @throws IllegalArgumentException if {@literal id} is {@literal null}.
     */
    boolean existsById(ID id);

    /**
     * Returns all instances of the type.
     *
     * @return all entities
     */
    Iterable<T> findAll();

    /**
     * Returns all instances of the type {@code T} with the given IDs.
     * <p>
     * If some or all ids are not found, no entities are returned for these IDs.
     * <p>
     * Note that the order of elements in the result is not guaranteed.
     *
     * @param ids must not be {@literal null} nor contain any {@literal null} values.
     * @return guaranteed to be not {@literal null}. The size can be equal or less than the number of given
     *         {@literal ids}.
     * @throws IllegalArgumentException in case the given {@link Iterable ids} or one of its items is {@literal null}.
     */
    Iterable<T> findAllById(Iterable<ID> ids);

    /**
     * Returns the number of entities available.
     *
     * @return the number of entities.
     */
    long count();

    /**
     * Deletes the entity with the given id.
     *
     * @param id must not be {@literal null}.
     * @throws IllegalArgumentException in case the given {@literal id} is {@literal null}
     */
    void deleteById(ID id);

    /**
     * Deletes a given entity.
     *
     * @param entity must not be {@literal null}.
     * @throws IllegalArgumentException in case the given entity is {@literal null}.
     */
    void delete(T entity);

    /**
     * Deletes the given entities.
     *
     * @param entities must not be {@literal null}. Must not contain {@literal null} elements.
     * @throws IllegalArgumentException in case the given {@literal entities} or one of its entities is {@literal null}.
     */
    void deleteAll(Iterable<? extends T> entities);

    /**
     * Deletes all entities managed by the repository.
     */
    void deleteAll();
}
CrudRepository

我们的MyUserDao只需要集成PagingAndSortingRepository就可以直接使用上述接口中的方法。

创建UserDao.java

import org.springframework.data.repository.PagingAndSortingRepository;


public interface MyUserDao extends PagingAndSortingRepository<User,Integer> {
}

 

测试

import com.wsz.example.elasticsearch.entity.index.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
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.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;

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

@SpringBootTest
@Slf4j
class MyUserDaoTest {

    @Autowired
    private MyUserDao myUserDao;

    @Test
    void getAll(){
        Iterable<User> all = myUserDao.findAll();
        AggregatedPageImpl<User> page = (AggregatedPageImpl<User>)all;
        log.info("content:{}",page.getContent());
    }

    @Test
    void getAllByIds(){
        List<Integer> ids = new ArrayList<>();
        ids.add(1001);
        ids.add(1002);
        ids.add(1003);
        Iterable<User> all = myUserDao.findAllById(ids);
        log.info("content:{}",all.toString());
    }

    @Test
    void count(){
        long count = myUserDao.count();
        log.info(count+"");
    }

    @Test
    void saveOneEntity(){
        User user = new User();
        user.setId(1);
        user.setName("唐僧");
        user.setAge(18);
        user.setDesc("三藏,御弟,金蝉子");
        user.setLike("西天取经,讲经说法");
        user.setPhone("13453345678");
        User save = myUserDao.save(user);
        System.out.println(save.toString());
    }

    @Test
    void saveAll(){
        User user = new User();
        user.setId(1002);
        user.setName("孙悟空");
        user.setAge(1500);
        user.setDesc("孙行者,猴子,猴哥,斗战胜佛");
        user.setLike("吃桃,打妖怪");
        user.setPhone("123456789");

        User user2 = new User();
        user2.setId(1003);
        user2.setName("猪悟能");
        user2.setAge(1500);
        user2.setDesc("净坛使者,老猪,八戒");
        user2.setLike("美女,美食,美酒,分家");
        user2.setPhone("123456789");

        List<User> list = new ArrayList<>();
        list.add(user);
        list.add(user2);

        Iterable<User> users = myUserDao.saveAll(list);
        log.info(users.toString());
    }

    @Test
    void findById(){
        Optional<User> byId = myUserDao.findById(1002);
        System.out.println(byId.toString());
    }

    @Test
    void existsById(){
        boolean exists = myUserDao.existsById(1002);
        log.info("1002:{}",exists);
        boolean exists2 = myUserDao.existsById(1001);
        log.info("1001:{}",exists2);
    }

    @Test
    void deleteById(){
        myUserDao.deleteById(1002);
        System.out.println("1002");
    }

    @Test
    void deleteByIds(){
        User user2 = new User();
        user2.setId(1003);
        user2.setName("猪悟能");
        user2.setAge(1500);
        user2.setDesc("净坛使者,老猪,八戒");
        user2.setLike("美女,美食,美酒,分家");
        user2.setPhone("123456789");

        List<User> list = new ArrayList<>();
        list.add(user2);
        myUserDao.deleteAll(list);
        getAll();
    }

    @Test
    void findAllWithSort(){
        Sort sort = Sort.by(Sort.Direction.DESC, "age");
        Iterable<User> all = myUserDao.findAll(sort);
        log.info(all.toString());
    }

    @Test
    void findAllWithPage(){
        Page<User> all = myUserDao.findAll(PageRequest.of(0, 3));
        AggregatedPageImpl<User> page = (AggregatedPageImpl<User>)all;
        log.info(page.getContent().toString());
    }
}
MyUserDaoTest

 

利用Spring data JPA,根据属性名进行组合检索

显而易见,上述检索接口最多是以ID、排序、分页为参数进行检索,那如何定制化检索呢?

可以通过继承Repository<T,ID> 接口,通过属性名和操作命进行检索

 创建MyUserSearchDao.java。

import org.springframework.data.repository.Repository;
import java.util.Collection;
import java.util.List;


public interface MyUserSearchDao extends Repository<User,Integer> {
    //{"bool" : {"must" : {"field" : {"name" : "?"}}}}
    List<User> findByName(String name);

    //{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"age" : "?"}} ]}}
    List<User> findByNameAndAge(String name);

    //{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"age" : "?"}} ]}}
    List<User> findByNameOrAge(String name, Integer age);

    //{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
    List<User> findByNameNot(String name);

    //{"bool" : {"must" : {"range" : {"age" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
    List<User> findByAgeBetween(Object from,Object to);

    //{"bool" : {"must" : {"range" : {"age" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
    List<User> findByAgeLessThanEqual(double lessThan);
    List<User> findByAgeBefore(double lessThan);


    //{"bool" : {"must" : {"range" : {"age" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
    List<User> findByAgeGreaterThanEqual(double greaterThan);
    List<User> findByAgeAfter(double greaterThan);

    //{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
    List<User> findByNameLike(String name);

    //{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
    List<User> findByNameStartingWith(String prefix);

    //{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
    List<User> findByNameEndingWith(String suffix);

    //{"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}
    List<User> findByNameContaining(String name);

    //{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
    List<User> findByNameIn(Collection<String> names);

    //{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
    List<User> findByNameNotIn(Collection<String> names);
}

 

以上各接口均是通过以下组合而来。

 

自定义检索

如果上述按属性名称进行检索还不能满足需求,可以考虑自定义检索。

关于这个功能,目前还没找到和PagingAndSortingRepository一样,只一个接口继承就可以,不需要再继承PagingAndSortingRepository实现类的方法,如果各位有相关方法,麻烦评论里留个痕迹。

 

我先把结构晒出来,检索内容根据个人需要自行处理即可。

新建repository包,包中包含检索的接口类和实现类

 

CustomElasticsearchRepository.java

import com.wsz.example.elasticsearch.entity.query.ComplexQuery;
import java.util.List;

public interface CustomElasticsearchRepository<T,ID> {

    List<T> complexPage(ComplexQuery complexQuery);

}

这里主要提供检索接口。Complex.java为包含检索参数的类。

@Data
public class ComplexQuery {

    private List<String> queryFields;

    private List<String> highLightFields;

    private List<QueryCondition> query;

    private String sortField;

    private String orderType;

    private Integer pageIndex;

    private Integer pageSize;

    public Integer getPageIndex() {
        return (pageIndex-1) * this.pageSize;
    }
}
ComplexQuery

 

AbstractCustomElasticsearchRepository.java

这里对检索功能进行具体的实现

import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;


@Slf4j
public class AbstractCustomElasticsearchRepository<T,ID> implements CustomElasticsearchRepository<T,ID> {

    protected ElasticsearchOperations operations;

    protected Class<T> clazz;

    public AbstractCustomElasticsearchRepository(ElasticsearchOperations operations) {
        this.operations = operations;
    }


    @Override
    public List<T> complexPage(ComplexQuery complexQuery)  {
        List<T> list = new ArrayList<>();
        //todo 检索实现
        return list;
    }

    //获取T的具体类
    protected Class<T> getJavaType() {

        if (!isEntityClassSet()) {
            try {
                this.clazz = resolveReturnedClassFromGenericType();
            } catch (Exception e) {
                throw new InvalidDataAccessApiUsageException("Unable to resolve EntityClass. Please use according setter!", e);
            }
        }
        return clazz;
    }

    private boolean isEntityClassSet() {
        return clazz != null;
    }

    @SuppressWarnings("unchecked")
    private Class<T> resolveReturnedClassFromGenericType() {
        ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass());
        return (Class<T>) parameterizedType.getActualTypeArguments()[0];
    }

    private ParameterizedType resolveReturnedClassFromGenericType(Class<?> clazz) {
        Object genericSuperclass = clazz.getGenericSuperclass();

        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type rawtype = parameterizedType.getRawType();
            if (SimpleElasticsearchRepository.class.equals(rawtype)) {
                return parameterizedType;
            }
        }

        return resolveReturnedClassFromGenericType(clazz.getSuperclass());
    }
}

 

可以通过具体接口和具体实现类的方式来调用。

public interface ICustomUserDao extends CustomElasticsearchRepository<User,Integer> {

}

 

@Repository
public class ICustomUserDaoImpl extends AbstractCustomElasticsearchRepository<User, Integer> implements ICustomUserDao {

    public ICustomUserDaoImpl(ElasticsearchOperations operations) {
        super(operations);
        this.clazz = User.class;
    }
}

 

posted @ 2022-08-24 14:36  代码羡  阅读(626)  评论(0编辑  收藏  举报