elasticsearch搜索引擎的常用方法

蚊子 2023年04月16日 389次浏览

前言

本次使用的elasticsearch是7.x,与6.x相比,可以无需指定doc

准备

application.yml

配置连接地址,在spring下

spring:
  elasticsearch:
    rest:
      uris: http://47.92.173.115:92000

image-1681660394759

依赖

<dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.7.1</version>
        </dependency>

工具类

JsonUtil类

package com.yikekong.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.io.IOException;

public class JsonUtil{
    /**
     * 反序列化
     * @param json
     * @param clazz
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> T getByJson(String json, Class<T> clazz) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        // 在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //反序列化"2020-01-22T11:11:11"字符串为LocalDateTime格式的配置
        mapper.registerModule(new JavaTimeModule());

        return mapper.readValue(json, clazz);
    }

    /**
     * 从json字符串中根据nodeName获取值
     * @param nodeName
     * @param json
     * @return
     * @throws IOException
     */
    public static String getValueByNodeName(String nodeName, String json) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.readTree(json);

        return jsonNode.findPath(nodeName).asText();
    }

    /**
     * 序列化
     * @param object
     * @return
     * @throws JsonProcessingException
     */
    public static String serialize(Object object) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        // 在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //反序列化"2020-01-22T11:11:11"字符串为LocalDateTime格式的配置
        mapper.registerModule(new JavaTimeModule());

        return mapper.writeValueAsString(object);
    }
}

代码

形参是个DeviceDTO,是个实体类,不是系统自带的

导入

@Autowired
    private RestHighLevelClient restHighLevelClient;

插入/添加

根据传来的实体类,进行添加

 public void createadd(DeviceDTO devicedt) throws Exception{
        if(StringUtils.isEmpty(devicedt))
            return;
        if(devicedt.getDeviceId()==null)
            return;
        //设置那个库插入数据
        IndexRequest indexRequest = new IndexRequest("devices");
        //将传过来的数据转成json
        String serialize = JsonUtil.serialize(devicedt);

        //因为搜索引擎要的数据源是Map,所以将json转成Map
        Map byJson = JsonUtil.getByJson(serialize, Map.class);
        indexRequest.source(byJson);
        indexRequest.id(devicedt.getDeviceId());

        //将东西告诉es,启动插入/添加 可以理解启动搜索服务器
        restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println("添加ok");

    }

条件搜索

根据传过来的id,进行搜索

public DeviceDTO deviceDTO(String deviceId) throws Exception{
        //去那个库搜索
        SearchRequest searchRequest = new SearchRequest("devices");


        //设置搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //_id对应搜索引擎里面的,deviceId是形参
        searchSourceBuilder.query(QueryBuilders.termQuery("_id",deviceId));
        //将传入的id值,进行封装文档格式,准备告诉es
        searchRequest.source(searchSourceBuilder);


        //将东西告诉es,启动搜索 可以理解启动搜索服务器
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //获取结果中hits里面的内容,这里返回的数据有很多
        //很多意思是,里面不只有我们需要的数据,还有一些其它参数
        //所以下面不能直接判断它是不是空
        SearchHits hits = search.getHits();

        //获取数据几条,这就是为什么不能直接判断上面是不是空
        long value = hits.getTotalHits().value;
        if(value<=0){
            return null;
        }

        DeviceDTO deviceDTO = null;
        for (SearchHit hit : hits) {
            //获取我们需要的数据,但返回是json格式
            String sourceAsString = hit.getSourceAsString();
            //转换到实体类对象
            deviceDTO = JsonUtil.getByJson(sourceAsString,DeviceDTO.class);
            break;
        }
        return deviceDTO;

    }

修改/更新数据

传入要修改的id和要改成什么状态

 //修改/更新数据
    //这里要说下,根据id更新状态 我的状态是true和false

    //如果更新成功返回true,失败就会报错,进入catch返回false
    public boolean update(String deviceId,boolean status){
        UpdateRequest updateRequest = new UpdateRequest("devices",deviceId).doc("status",status);
        UpdateResponse update = null;
        try {
            update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

多参数修改修改/更新

根据穿过来实体类,进行修改/更新

 public boolean updateDeviceAlarm(DeviceDTO dto){
 //双引号里面的搜索搜索引擎的
        UpdateRequest updateRequest = new UpdateRequest("devices",dto.getDeviceId()).doc("alarm",dto.getAlarm(),"alarmName",dto.getAlarmName(),"level",dto.getLevel());
        try {
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            return false;
        }
        return true;
    }

条件分页

//条件分页
    public Pager<DeviceDTO> page(Long pageIndex,Long pageSize, String deviceId, String tag, Integer state){
        SearchRequest indexRequest = new SearchRequest("devices");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //多个查询条件使用
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //判断是否为空,返回值是boolen型
        if(!Strings.isNullOrEmpty(deviceId)){
            
        //QueryBuilders.wildcardQuery代表模糊查询方法
        boolQueryBuilder.must(QueryBuilders.wildcardQuery("deviceId",deviceId+"*"));
        }
        if(!Strings.isNullOrEmpty(tag)){
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("tag","*"+tag+"*"));
        }

        //对于不确定的值,进行进一步判断
        //状态(在线状态和告警状态)  0:在线  1:离线  2:一般告警  3:严重告警
        if(state!=null){
            //666
       if(state.intValue()==0){
           System.out.println("开始0");
           System.out.println(state.intValue());
           System.out.println(state);
           System.out.println("结束0");
           //QueryBuilders.termQuery代表精准查询方法
           boolQueryBuilder.must(QueryBuilders.termQuery("online",true));
       }else if (state.intValue() == 1){
           boolQueryBuilder.must(QueryBuilders.termQuery("online",false));
       }else if (state.intValue() == 2) {
         boolQueryBuilder.must(QueryBuilders.termQuery("level",1));
       }else if (state.intValue() == 3) {
           boolQueryBuilder.must(QueryBuilders.termQuery("level",2));
       }else {
           boolQueryBuilder.must(QueryBuilders.termQuery("level",0));
       }
        }

        //设置查询条件
        searchSourceBuilder.query(boolQueryBuilder);
        //设置第几页
        searchSourceBuilder.from((pageIndex.intValue()-1)*pageSize.intValue());
        //设置一页几条数据
        searchSourceBuilder.size(pageSize.intValue());
        //封装,准备告诉es
        indexRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = restHighLevelClient.search(indexRequest, RequestOptions.DEFAULT);
            SearchHits hits = search.getHits();
            long valu22e = hits.getTotalHits().value;
            if(valu22e<=0){
                return null;
            }
            List<DeviceDTO> li = new ArrayList<>();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                DeviceDTO byJson = JsonUtil.getByJson(sourceAsString, DeviceDTO.class);
                li.add(byJson);
            }
            //设置分页对象
            Pager<DeviceDTO> pager = new Pager<>(valu22e,pageSize);
            //设置分页数据
            pager.setItems(li);
            return pager;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }

统计总数

统计搜索引擎里面所有数量

public Long getAllDeviceCount(){

    CountRequest countRequest=new CountRequest("devices");
    countRequest.query( QueryBuilders.matchAllQuery() );
    try {
        CountResponse response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        return response.getCount();
    } catch (IOException e) {
        e.printStackTrace();
        return 0L;
    }
}

条件统计

根据状态,统计总数

 public Long getOfflineCount(boolean state){

        CountRequest countRequest=new CountRequest("devices");
        BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();
        //online是搜索引擎里面的
        boolQueryBuilder.must( QueryBuilders.termQuery("online",state)  );
        //如需多个条件,复制上面一行,即可

        countRequest.query( boolQueryBuilder );

        try {
            CountResponse response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            return response.getCount();
        } catch (IOException e) {
            e.printStackTrace();
            return 0L;
        }

    }

GPS定位

第一个:就是画圆,直线到达,看看距离够不够
第二个:一个正方形,根据2个点,画一个正方形,里面的数据全给拿出来
第三个:多个点,画图,图里面的数据全给你拿出来
image-1685777019993
image-1685777219692

代码:
这个代码晚上用的画圆,也就是第一个

@Override
public List<VmInfoDTO> search(VmSearch searchReq) {
    //指定索引
    SearchRequest searchRequest = new SearchRequest("vm");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

    //中心点及半径构建
    GeoDistanceQueryBuilder geoDistanceQueryBuilder = new GeoDistanceQueryBuilder("location");
    geoDistanceQueryBuilder.distance(searchReq.getDistance(), DistanceUnit.KILOMETERS);
    geoDistanceQueryBuilder.point(searchReq.getLat(),searchReq.getLon());

    //从近到远排序规则构建
    GeoDistanceSortBuilder distanceSortBuilder = new GeoDistanceSortBuilder("location",searchReq.getLat(),searchReq.getLon());
    distanceSortBuilder.unit(DistanceUnit.KILOMETERS);
    distanceSortBuilder.order(SortOrder.ASC);
    distanceSortBuilder.geoDistance(GeoDistance.ARC);
            
    BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

    boolQueryBuilder.must(geoDistanceQueryBuilder);
    searchSourceBuilder.query(boolQueryBuilder);
    searchSourceBuilder.sort(distanceSortBuilder);

    searchRequest.source(searchSourceBuilder);
    try {
        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        if(hits.getTotalHits().value <= 0){
            return Lists.newArrayList();
        }
        List<VmInfoDTO> vmInfoList = Lists.newArrayList();
        Arrays.stream(hits.getHits()).forEach(h->{
            VmInfoDTO vmInfo = null;
            try {
                vmInfo = JsonUtil.getByJson(h.getSourceAsString(), VmInfoDTO.class);
                //将千米转换为米
                BigDecimal geoDis=new BigDecimal((double)h.getSortValues()[0]*1000);
                vmInfo.setDistance(geoDis.intValue());
            } catch (IOException e) {
                log.error("convert vminfo error",e);
            }
            if(vmInfo!=null){
                vmInfoList.add(vmInfo);
            }
        });
        return vmInfoList;
    } catch (IOException e) {
        log.error("search location error",e);
        return Lists.newArrayList();
    }
}