记录使用spring-data-elasticsearch过程中遇到的问题。增加通用自定义接口

          公司有业务需求APP端坐标需要不停的上传,根据业务量,每个月可能会产生大概20G的数据,现有的解决方案是直接存储在oracle中根据每月进行分表存储。但是不可避免的随着时间的拉长,处理起来越来越不方便,于是便想到了使用es来存储,后面查询时也比较方便。

         为了让操作方式与以前存储保持一致,保持增删查改分页查询等的需求。直接使用的spring-data-elasticsearch,只要继承ElasticsearchRepository,就可以实现简单的CURD操作,因为public interface ElasticsearchRepository<T, ID extends Serializable> extends ElasticsearchCrudRepository<T, ID>。首先发现这个没有修改的方法,即直接传入一个实体,对里面的字段就行修改,还有就是对分页的查询,以前我们使用的mybatisplus进行分页,传过来的分页参数和自带的不一致,以及以后的存储为动态索引,这个自带的只能查询当前索引。为了让开发人员更方便的使用,自己增加了这几个方法,以后他们开发过程中,需要继承ElasticsearchRepository的地方,直接继承我的这个接口就可以了。

@NoRepositoryBean
public interface MyEsRepository<T, ID extends Serializable> extends ElasticsearchRepository<T, ID> {
    default Page getPage(T bean, Page page,QueryBuilder... queryBuilder){
        BoolQueryBuilder qb =getBoolQueryBuilder(bean);
        for(QueryBuilder queryBuilder1:queryBuilder){
            qb.filter(queryBuilder1);
        }

        Pageable pageRequest=getPageable(page);
        org.springframework.data.domain.Page<T> search = this.search(qb,pageRequest);
        page.setRecords(search.getContent());
        return page;
    };

    @SneakyThrows
    default boolean update(T bean){
        Class<T> tClass=this.getEntityClass();
        ID id=null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(tClass);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            Field[] declaredFields = tClass.getDeclaredFields();
            for(Field field:declaredFields){
                Id annotation = field.getAnnotation(Id.class);
                if(annotation!=null || field.getName().equalsIgnoreCase("id")){
                    field.setAccessible(true);
                    id=(ID)field.get(bean);
                    break;
                }
            }

            T oldBean=this.findById(id).get();
            if(oldBean==null){
                this.save(bean);
            }else{
                for (PropertyDescriptor property : propertyDescriptors) {
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(bean);
                    if(value!=null &&(!property.getName().equals("class"))){
                        Field f = tClass.getDeclaredField(property.getName());
                        f.setAccessible(true);
                        f.set(oldBean, value);
                    }
                }
                this.save(oldBean);
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }
        return true;
    }

    default BoolQueryBuilder getBoolQueryBuilder(T bean){
        Map<String,Object> map= BeanUtils.beanToMap(bean,false);
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        if(map!=null){
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery(entry.getKey(),entry.getValue());
                queryBuilder.minimumShouldMatch("100%");
                qb.filter(queryBuilder);
            }
        }
        return qb;
    }

    default Pageable getPageable(Page page){
        List<OrderItem> orders = page.getOrders();
        Pageable pageRequest;
        if(orders.size()>0){
            List<String> asc=new ArrayList();
            List<String> desc=new ArrayList();
            orders.forEach(item->{
                if(item.isAsc()){
                    asc.add(item.getColumn());
                }else{
                    desc.add(item.getColumn());
                }
            });
            Sort sort;
            if(asc.size()>0 && desc.size()>0){
                sort=new Sort(Sort.Direction.ASC,asc);
                Sort sort1=new Sort(Sort.Direction.DESC,desc);
                sort.and(sort1);
            }else if(asc.size()>0){
                sort=new Sort(Sort.Direction.ASC,asc);
            }else{
                sort=new Sort(Sort.Direction.DESC,desc);
            }
            pageRequest = PageRequest.of(Long.valueOf(page.getCurrent()).intValue()-1,
                    Long.valueOf(page.getSize()).intValue(),sort);
        }else{
            pageRequest = PageRequest.of(Long.valueOf(page.getCurrent()).intValue()-1,
                    Long.valueOf(page.getSize()).intValue());
        }
        return pageRequest;
    }


    default Page getAllPage(T bean, Page page,int DyMonth,ElasticsearchTemplate elasticsearchTemplate, QueryBuilder... queryBuilder){

        BoolQueryBuilder qb =getBoolQueryBuilder(bean);
        Pageable pageRequest=getPageable(page);
        Class<T> tClass=this.getEntityClass();
        Document annotation = tClass.getAnnotation(Document.class);
        String[] indexName = annotation.indexName().split("_");
        String[] indexs=new String[DyMonth];
        for(int i=0;i<DyMonth;i++){
            indexs[i]=indexName[0]+"_"+ Date8Util.minusMonthstoString(i);
        }
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withIndices(indexs).withQuery(qb)
                .withPageable(pageRequest);
        for(QueryBuilder queryBuilder1:queryBuilder){
            nativeSearchQueryBuilder.withQuery(queryBuilder1);
        }
        List<T> esGpsStatuses = elasticsearchTemplate.queryForList(nativeSearchQueryBuilder.build(), tClass);
//        org.springframework.data.domain.Page<T> search = this.search(qb,pageRequest);
        page.setRecords(esGpsStatuses);
        return page;
    };

    default String getIndex(){
        Class<T> tClass=this.getEntityClass();
        Document annotation = tClass.getAnnotation(Document.class);
        String[] indexName = annotation.indexName().split("_");
        return indexName[0];
    }





}

分页查询,增加了动态参数,为了方便他们自己进行设置查询参数。

       然后开始开发,首先测试排序,我们是对时间进行排序查询,发现报错all shards failed。原来排序的字段需要设置fielddata=true。经测试FieldSortBuilder idSort = SortBuilders.fieldSort("systemtime").order(SortOrder.ASC).unmappedType("Date");通过这种方式设置不管用。因为es里已经存在数据了,需要去修改mapping.或者删了索引,重新来哈。不过在建实体的时候对需要排序的字段加上@Field(fielddata=true),不过存储的时候需要记住,这个字段不能为空了,如果存储的时候存了空,后面对该字段排序查询的时候还是会报错。

      动态索引,开始想在AbstractElasticsearchRepository或者ElasticsearchRepositoryFactory里面想办法,又或者直接取到对应的bean,然后定时任务去修改里面的index等等。最后发现可以直接简单的使用el表达式就可以了,哪来的那么麻烦@Document(indexName = "gps_"+"#{T(com.my.common.core.util.Date8Util).getYearMonth()}")......,不过要是没事的时候也可以去尝试一下..

     然后分页查询后,我们业务需求是对某个时间段进行查询,而我们使用的是Date,开始以为和其他的一样,只要存储的时候和查询都是一样的类型, 就没问题了,然后才发现,存储没问题,但是实际上存储进去是保存timestarp。后面查询时,如果传入Date类型。

 RangeQueryBuilder rangeQueryBuilder= QueryBuilders.rangeQuery("uploadtime");
        if(esQuery.getUploadTimes()!=null){
            rangeQueryBuilder.from(esQuery.getUploadTimes());
        }
        if(esQuery.getUploadTimee()!=null){
            rangeQueryBuilder.to(esQuery.getUploadTimee());
        }

没想到这样会报错,java.lang.NumberFormatException: For input string: 。查看源码,原来都会转换为string然后进行判断,然后把Date转换一下.getTime()解决了问题。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值