package com.yeejoin.amos.boot.module.elevator.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.module.elevator.api.dto.ESAlertCalledDto;
import com.yeejoin.amos.boot.module.elevator.api.dto.EsElevatorDto;
import com.yeejoin.amos.boot.module.elevator.api.dto.EsSpecialEquipmentDto;
import com.yeejoin.amos.boot.module.elevator.api.dto.EsSpecialEquipmentListDto;
import com.yeejoin.amos.boot.module.elevator.api.dto.SpecialEquipmentDto;
import com.yeejoin.amos.boot.module.elevator.api.entity.AlertCalled;
import com.yeejoin.amos.boot.module.elevator.api.entity.Elevator;
import com.yeejoin.amos.boot.module.elevator.api.entity.EsElevator;
import com.yeejoin.amos.boot.module.elevator.api.mapper.SuperviseInfoMapper;
import com.yeejoin.amos.boot.module.elevator.biz.dao.ESElavtorRepository;
import com.yeejoin.amos.feign.systemctl.model.RegionModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.geo.GeoBoundingBox;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.filter.Filters;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoHashGridAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.geogrid.ParsedGeoHashGrid;
import org.elasticsearch.search.aggregations.bucket.geogrid.ParsedGeoHashGridBucket;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.stereotype.Service;
import org.springframework.util.StopWatch;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 * <pre>
 * 电梯信息ES检索服务
 * </pre>
 *
 * @authorlitw
 * @version  2021年9月26日
 */
@Service
@Slf4j
public class ESElevatorServiceImpl {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;

    @Autowired
    private ESElavtorRepository esElavtorRepository;

    @Autowired
    AlertCalledServiceImpl iAlertCalledService;


    @Autowired
    private SuperviseInfoMapper superviseInfoMapper;

    @Value("${alertcall.es.synchrony.time}")
	private Long time;
    

//      数据源切换
//    /**
//     *
//     * <pre>
//     * 电梯信息
//     * </pre>
//     *
//     * @param elevator 电梯信息
//     */
//    public EsElevator saveEsElevatorToES(Elevator elevator)
//    {
//		EsElevator esElevator = new EsElevator();
//        if(StringUtils.isNotEmpty(elevator.getLongitude())) {
//            esElevator.setLongitude(Double.parseDouble(elevator.getLongitude()));
//        }
//        if(StringUtils.isNotEmpty(elevator.getLatitude())) {
//            esElevator.setLatitude(Double.parseDouble(elevator.getLatitude()));
//        }
//        esElevator.setAddress(elevator.getAddress());
//        esElevator.setCity(elevator.getCity());
//        esElevator.setDistrict(elevator.getDistrict());
//        esElevator.setProvince(elevator.getProvince());
//        esElevator.setRegionCode(elevator.getRegionCode());
//        esElevator.setRescueCode(elevator.getRescueCode().toString());
//        esElevator.setRegisterCode(elevator.getRegisterCode());
//        esElevator.setSequenceNbr(elevator.getSequenceNbr());
//        esElevator.setInnerNum(elevator.getInnerNum());
//        if(StringUtils.isNotBlank(elevator.getLatitude()) && StringUtils.isNotBlank(elevator.getLongitude())) {
//            Double lat = Double.parseDouble(elevator.getLatitude());
//            Double lon = Double.parseDouble(elevator.getLongitude());
//            esElevator.setLocation(new GeoPoint(lat,lon));
//        }
//		esElavtorRepository.save(esElevator);
//    	return esElevator;
//    }


    public ESElavtorRepository getESElavtorRepository(){
        return esElavtorRepository;
    };

    /**
     * 根据关键字查询文档，关键字不为空时按相关性从大到小排序
     *
     * @param elevatorDto 关键字
     * @return
     */
    @SuppressWarnings({ "rawtypes" })
    public List<EsElevatorDto> queryByKeys(EsElevatorDto elevatorDto) {

        String alarmTypeCode = elevatorDto.getAlarmTypeCode();
        String address = elevatorDto.getAddress();
        String regionCode = elevatorDto.getRegionCode();
        String alertId = elevatorDto.getAlertId();
        String equipmentId = elevatorDto.getSequenceNbr();

        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        BoolQueryBuilder qb0 = QueryBuilders.boolQuery();
        LambdaQueryWrapper<AlertCalled> queryWrapper = new LambdaQueryWrapper();

        if(!ValidationUtil.isEmpty(alarmTypeCode) && !"all".equals(alarmTypeCode)) {
            queryWrapper.eq(AlertCalled::getAlarmTypeCode,alarmTypeCode);
        }
        AlertCalled alertCalled = null;
        List<AlertCalled> alertCalleds = null;
        if(!ValidationUtil.isEmpty(alertId)) {
            alertCalled = iAlertCalledService.getById(elevatorDto.getAlertId());
            BoolQueryBuilder qb4 = QueryBuilders.boolQuery();
            qb4.must(QueryBuilders.termQuery("sequenceNbr",  alertCalled.getEquipmentId()));
            boolMust.must(qb4);
        } else {
            if(!ValidationUtil.isEmpty(alarmTypeCode)) {
                if(elevatorDto.getIsToday() != null && elevatorDto.getIsToday()) {
                    queryWrapper.ge(AlertCalled::getCallTime, DateUtils.stampToDate(System.currentTimeMillis(),DateUtils.DATE_PATTERN));
                    queryWrapper.le(AlertCalled::getCallTime, DateUtils.stampToDate(DateUtils.dateAddDays(new Date(),1).getTime(),DateUtils.DATE_PATTERN));
                }
                alertCalleds  = iAlertCalledService.list(queryWrapper);
                List<String> stringList = new ArrayList<>();
                for (AlertCalled al: alertCalleds
                ) {
                    stringList.add(al.getEquipmentId());
                }
                List<String> listL = stringList.stream().distinct().collect(Collectors.toList());
                qb0.should(QueryBuilders.termsQuery("sequenceNbr",  listL.toArray()));
                boolMust.must(qb0);
            }
        }


        if(!ValidationUtil.isEmpty(address)) {
            BoolQueryBuilder boolMustAddress = QueryBuilders.boolQuery();
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchPhraseQuery("address", address));
            boolMustAddress.should(qb1);
            boolMust.must(boolMustAddress);
        }

        if(!ValidationUtil.isEmpty(regionCode)) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", regionCode));
            boolMust.must(qb2);
        }

        if(!ValidationUtil.isEmpty(equipmentId)) {
            BoolQueryBuilder qb3= QueryBuilders.boolQuery().
                    filter(QueryBuilders. termQuery("sequenceNbr", equipmentId));
            boolMust.must(qb3);
        }

        // 创建查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                // 分页
                .withPageable(PageRequest.of(0, 3000))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust);


        List<EsElevatorDto> list = new LinkedList<>();
        try
        {
            SearchHits<EsElevator> searchHits =elasticsearchTemplate.search(queryBuilder.build(), EsElevator.class);

            for (SearchHit searchHit : searchHits.getSearchHits())
            {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
                EsElevatorDto esElevatorDto =JSONObject.toJavaObject(jsonObject, EsElevatorDto.class);
                if(null != alertCalleds) {
                    for (AlertCalled al: alertCalleds
                    ) {
                        if(al.getEquipmentId().equals(esElevatorDto.getSequenceNbr())) {
                            esElevatorDto.setHappenTime(al.getCallTime());
                            esElevatorDto.setAlertId(String.valueOf(al.getSequenceNbr()));
                            esElevatorDto.setAlarmTypeCode(al.getAlarmTypeCode());
                            esElevatorDto.setType(al.getAlertStage());
                            list.add(esElevatorDto);
                            break;
                        }
                    }
                } else {
                    list.add(esElevatorDto);
                }
            }
        }
        catch (Exception e)
        {
            // TODO: handle exception
        }
        return list;
    }


    /**
     * 根据特种设备搜索类查找电梯相关信息
     * @param esSpecialEquipmentDto
     * @return
     */
    public List<SpecialEquipmentDto> queryByDto(EsSpecialEquipmentDto esSpecialEquipmentDto) {

        Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
        Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
        Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
        Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
        String regionCode = esSpecialEquipmentDto.getRegionCode();
        String keyword = esSpecialEquipmentDto.getKeyword();
        // 如果传入经纬度则根据经纬度过滤 如果传入regionCode 根据regionCode过滤 如果是 单独查电梯 则返回最多3000条 否则为 400条
        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();


        // 经度比start 大比end 小 纬度比start 小 比end 大
        if(!ValidationUtil.isEmpty(startLongitude) && !ValidationUtil.isEmpty(startLatitude)  && !ValidationUtil.isEmpty(endLongitude)  && !ValidationUtil.isEmpty(endLatitude)) {
            BoolQueryBuilder longLatMust = QueryBuilders.boolQuery();
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("longitude").gte(startLongitude).lte(endLongitude));
            BoolQueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("latitude").gte(endLatitude).lte(startLatitude));
            longLatMust.must(qb1);
            longLatMust.must(qb2);
            boolMust.must(longLatMust);
        }

        if(!ValidationUtil.isEmpty(regionCode)) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", regionCode));
            boolMust.must(qb2);
        }

        if(!ValidationUtil.isEmpty(keyword)) {
            BoolQueryBuilder qb0 = QueryBuilders.boolQuery().
                    must(QueryBuilders.matchQuery("rescueCode.keyword", keyword));
            boolMust.should(qb0);
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery().
                    must(QueryBuilders.matchQuery("address", keyword));
            boolMust.should(qb1);
            boolMust.minimumShouldMatch(1);
        }

        // 创建查询构造器
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                // 分页
 //               .withPageable(PageRequest.of(0, size))
                // 排序
 //                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust).build();
        query.setTrackTotalHits(true);
        query.setMaxResults(10000);

        List<SpecialEquipmentDto> list = new LinkedList<>();
        SearchHits<EsElevator> searchHits =elasticsearchTemplate.search(query, EsElevator.class);
        for (SearchHit searchHit : searchHits.getSearchHits())
        {
            JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
            SpecialEquipmentDto esElevatorDto =JSONObject.toJavaObject(jsonObject, SpecialEquipmentDto.class);
            esElevatorDto.setCategoryCode("3000");
            list.add(esElevatorDto);
        }
        return list;

    }

    public List<SpecialEquipmentDto> queryListByDto(EsSpecialEquipmentListDto eSpecialEquipmentListDto) {
        Integer number = eSpecialEquipmentListDto.getEquipmentNumber();
        String regionCode = eSpecialEquipmentListDto.getRegionCode();
        // 如果传入经纬度则根据经纬度过滤 如果传入regionCode 根据regionCode过滤 如果是 单独查电梯 则返回最多3000条 否则为 400条
        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        if(!ValidationUtil.isEmpty(regionCode)) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", regionCode));
            boolMust.must(qb2);
        }
        if(number == null) {
            number = 3000;
        }

        // 创建查询构造器
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                // 分页
                .withPageable(PageRequest.of(0, number))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust).build();

        query.setTrackTotalHits(true);
        query.setMaxResults(10000);
        //queryBuilder.addAggregation()
        List<SpecialEquipmentDto> list = new LinkedList<>();
        SearchHits<EsElevator> searchHits =elasticsearchTemplate.search(query, EsElevator.class);
        for (SearchHit searchHit : searchHits.getSearchHits())
        {
            JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
            SpecialEquipmentDto esElevatorDto =JSONObject.toJavaObject(jsonObject, SpecialEquipmentDto.class);
            esElevatorDto.setCategoryCode("3000");
            list.add(esElevatorDto);
        }
        return list;
    }


    public List<Map<String, String>> queryTogetherByDto(EsSpecialEquipmentDto esSpecialEquipmentDto) {

        Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
        Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
        Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
        Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
        String regionCode = esSpecialEquipmentDto.getRegionCode();

        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        if(!ValidationUtil.isEmpty(regionCode)) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", regionCode));
            boolMust.must(qb2);
        }


        /**
         * 通用匹配规则，条件构建
         */
        List<Map<String, String>> result = new LinkedList<>();
        GeoPoint left = new GeoPoint(endLatitude, startLongitude);
        GeoPoint right = new GeoPoint(startLatitude, endLongitude);
        ConstantScoreQueryBuilder constantScore = new ConstantScoreQueryBuilder(new GeoBoundingBoxQueryBuilder("location").
                setCornersOGC(left,right));
        boolMust.must(constantScore);
        // 创建查询构造器

        NativeSearchQuery query = new NativeSearchQueryBuilder()
                // 分页
                //.withPageable(PageRequest.of(0, number))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust)
                .addAggregation(new GeoHashGridAggregationBuilder("96333")
                .precision(esSpecialEquipmentDto.getPrecision()).field("location")).build();
        query.setTrackTotalHits(true);
        query.setMaxResults(10000);
        SearchHits<EsElevator> searchHits = elasticsearchTemplate.search(query, EsElevator.class);
        Aggregations aggregations = searchHits.getAggregations();
        ParsedGeoHashGrid aggregation = aggregations.get("96333");
        List<? extends Terms.Bucket> buckets = (List<? extends Terms.Bucket>) aggregation.getBuckets();
        // 通过debug能看到aggregation.getBuckets里就是我所需要的分组信息，但是直接.出不来，这里我是手动拼出来并强转一下(ParsedLongTerms)
        for (int i = 0; i < buckets.size(); i++) {
            ParsedGeoHashGridBucket bucket = (ParsedGeoHashGridBucket) buckets.get(i);
            // 每组的key
            String key = bucket.getKeyAsString();            // bucket key
            long docCount = bucket.getDocCount();            // Doc count
            GeoPoint point = GeoPoint.fromGeohash(key);
            Map<String, String> tempMap = new HashMap<>();
            tempMap.put("lat",point.getLat() +"");
            tempMap.put("lon",point.getLon() + "");
            tempMap.put("number",docCount+"");
            result.add(tempMap);
        }

        return result;
    }

    public Page<SpecialEquipmentDto> queryPageByDto(EsSpecialEquipmentDto esSpecialEquipmentDto, int current, int size) {
        Page<SpecialEquipmentDto> result = new Page<SpecialEquipmentDto>(current, size);
        Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
        Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
        Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
        Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
        String regionCode = esSpecialEquipmentDto.getRegionCode();
        String keyword = esSpecialEquipmentDto.getKeyword();
        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 经度比start 大比end 小 纬度比start 小 比end 大
        if(!ValidationUtil.isEmpty(startLongitude) && !ValidationUtil.isEmpty(startLatitude)  && !ValidationUtil.isEmpty(endLongitude)  && !ValidationUtil.isEmpty(endLatitude)) {
            BoolQueryBuilder longLatMust = QueryBuilders.boolQuery();
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("longitude").gte(startLongitude).lte(endLongitude));
            BoolQueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("latitude").gte(endLatitude).lte(startLatitude));
            longLatMust.must(qb1);
            longLatMust.must(qb2);
            boolMust.must(longLatMust);
        }

        if(!ValidationUtil.isEmpty(regionCode)) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", regionCode));
            boolMust.must(qb2);
        }

        if(!ValidationUtil.isEmpty(keyword)) {
            BoolQueryBuilder qb0 = QueryBuilders.boolQuery().
                    must(QueryBuilders.matchQuery("rescueCode.keyword", keyword));
            boolMust.should(qb0);
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery().
                    must(QueryBuilders.matchQuery("address", keyword));
            boolMust.should(qb1);
            boolMust.minimumShouldMatch(1);
        }

        // 创建查询构造器
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                // 分页
                .withPageable(PageRequest.of(current-1, size))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust).build();
        query.setTrackTotalHits(true);
        query.setMaxResults(size);
        List<SpecialEquipmentDto> list = new LinkedList<>();
        long total = 0;
        try
        {
            SearchHits<EsElevator> searchHits =elasticsearchTemplate.search(query , EsElevator.class);

            for (SearchHit searchHit : searchHits.getSearchHits())
            {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
                SpecialEquipmentDto esElevatorDto =JSONObject.toJavaObject(jsonObject, SpecialEquipmentDto.class);
                esElevatorDto.setCategoryCode("3000");
                esElevatorDto.setInnerNum(ObjectUtils.isEmpty(esElevatorDto.getInnerNum()) || "null".equals(esElevatorDto.getInnerNum()) ? null : esElevatorDto.getInnerNum());
                list.add(esElevatorDto);
            }
            total =searchHits.getTotalHits();
        }
        catch (Exception e)
        {
            // TODO: handle exception
            e.printStackTrace();
        }
        result.setRecords(list);
        result.setTotal(total);
        return result;
    }

    public Long queryNumberByDto(EsSpecialEquipmentDto esSpecialEquipmentDto) {
        Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
        Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
        Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
        Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
        String regionCode = esSpecialEquipmentDto.getRegionCode();
        String keyword = esSpecialEquipmentDto.getKeyword();
        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 经度比start 大比end 小 纬度比start 小 比end 大
        if(!ValidationUtil.isEmpty(startLongitude) && !ValidationUtil.isEmpty(startLatitude)  && !ValidationUtil.isEmpty(endLongitude)  && !ValidationUtil.isEmpty(endLatitude)) {
            BoolQueryBuilder longLatMust = QueryBuilders.boolQuery();
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("longitude").gte(startLongitude).lte(endLongitude));
            BoolQueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("latitude").gte(endLatitude).lte(startLatitude));
            longLatMust.must(qb1);
            longLatMust.must(qb2);
            boolMust.must(longLatMust);
        }

        if(!ValidationUtil.isEmpty(regionCode)) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", regionCode));
            boolMust.must(qb2);
        }

        if(!ValidationUtil.isEmpty(keyword)) {
            BoolQueryBuilder qb0 = QueryBuilders.boolQuery().
                    must(QueryBuilders.matchQuery("rescueCode.keyword", keyword));
            boolMust.should(qb0);
            BoolQueryBuilder qb1 = QueryBuilders.boolQuery().
                    must(QueryBuilders.matchQuery("address", keyword));
            boolMust.should(qb1);
            boolMust.minimumShouldMatch(1);
        }

        // 创建查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                // 分页
//                .withPageable(PageRequest.of(current, size))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust);


        List<SpecialEquipmentDto> list = new LinkedList<>();
        long total = 0;
        try
        {
            SearchHits<EsElevator> searchHits =elasticsearchTemplate.search(queryBuilder.build(), EsElevator.class);
            total =searchHits.getTotalHits();
        }
        catch (Exception e)
        {
            // TODO: handle exception
        }
        return total;
    }


    public Map<String,Long> queryNumberByRegionCode(Map<String,RegionModel> regions) {

        /**
         * 通用匹配规则，条件构建
         */
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        for(Map.Entry<String,RegionModel> temp: regions.entrySet()) {
            BoolQueryBuilder qb2= QueryBuilders.boolQuery().
                    filter(QueryBuilders. matchPhraseQuery("regionCode", temp.getKey()));
            boolMust.should(qb2);
        }
        boolMust.minimumShouldMatch(1);
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("number").field("regionCode");

        // 创建查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                // 分页
//                .withPageable(PageRequest.of(current, size))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust).addAggregation(termsAggregationBuilder);

        SearchHits<EsElevator> searchHits =elasticsearchTemplate.search(queryBuilder.build(), EsElevator.class);
        Aggregations aggregations = searchHits.getAggregations();
        Terms aggregation = aggregations.get("number");
        Map<String,Long> result = new HashMap<>();
        for (Terms.Bucket bucket : aggregation.getBuckets()) {
            result.put(bucket.getKeyAsString(), bucket.getDocCount());
        }
        return result;
    }


    public void saveEsElevator2ES(List<Map<String, Object>> elevatorList, Long version) {
        StopWatch watch = new StopWatch();
        watch.start();
        List<EsElevator> esElevatorList = new ArrayList<>();
        List<String> recordList = new ArrayList<>();
        for (Map<String, Object> map : elevatorList) {
            EsElevator esElevator = new EsElevator();
            // 维度
            if (!ObjectUtils.isEmpty(map.get("longitude"))) {
                esElevator.setLongitude(Double.parseDouble(String.valueOf(map.get("longitude"))));
            }
            // 经度
            if (!ObjectUtils.isEmpty(map.get("latitude"))) {
                esElevator.setLatitude(Double.parseDouble(String.valueOf(map.get("latitude"))));
            }
            esElevator.setVersion(version);
            esElevator.setAddress(String.valueOf(map.get("address")));
            esElevator.setCity(String.valueOf(map.get("city")));
            esElevator.setDistrict(String.valueOf(map.get("district")));
            esElevator.setProvince(String.valueOf(map.get("province")));
            esElevator.setRegionCode(String.valueOf(map.get("regionCode")));
            esElevator.setRescueCode(String.valueOf(map.get("rescueCode")));
            esElevator.setRegisterCode(String.valueOf(map.get("registerCode")));
            esElevator.setSequenceNbr(String.valueOf(map.get("sequenceNbr")));
            esElevator.setInnerNum(String.valueOf(map.get("innerNum")));
            if (!ObjectUtils.isEmpty(map.get("longitude")) && !ObjectUtils.isEmpty(map.get("latitude"))) {
                // 经度 	-90° ~ 90°
                Double lat = Double.parseDouble(String.valueOf(map.get("latitude")));
                // 维度      -180° ~ 180°
                Double lon = Double.parseDouble(String.valueOf(map.get("longitude")));
                if(lat > 90 || lat < -90 || lon > 180 || lon < -180) {
                    log.warn("设备record：{},经纬度不正确, 不再记录GeoPoint",esElevator.getSequenceNbr());
                } else {
                    esElevator.setLocation(new GeoPoint(lat, lon));
                }
            }
            esElevatorList.add(esElevator);
            recordList.add(String.valueOf(map.get("sequenceNbr")));
        }
        StopWatch watch2 = new StopWatch();
        watch2.start();
        superviseInfoMapper.updateRecordBatch(recordList, version);
        watch2.stop();
        esElavtorRepository.saveAll(esElevatorList);
        log.info("批量更新：【{}】条业务数据，耗时：{} 毫秒", elevatorList.size(), watch2.getTotalTimeSeconds());
        watch.stop();
        log.info("创建电梯索引数据整体耗时：【{}】条业务数据，耗时：{} 毫秒", elevatorList.size(), watch.getTotalTimeSeconds());
    }
}
