使用elasticsearch 地理位置搜索 以及地理位置增删改查

DTO

import lombok.Data;

/**
 * @params 写入ES的一些通用方法
 * @Description
 * @Author Hc
 * @CreateUser: Hc
 * @CreateDate 2021/12/1 16:30
 * @Version 1.0
 * @Return
 **/
@Data
public class UnitToEsDTO{

    /**
     * 通用ID
     */
    private String id;

    /**
     * 经度
     */
    private Double longitude;

    /**
     * 维度
     */
    private Double latitude;

    /**
     * 地址
     */
    private String address;

    /**
     * 距离
     */
    private String distance;

    /**
     * 类型
     * 1 企业
     */
    private Integer type;


    private Double[] location;

    private String userId;

    private Integer start;

    private Integer limit;

}

地理位置搜索方法一

  public List<UnitToEsDTO> queryUnitByEs(UnitToEsDTO unitToEsDTO){
        List<UnitToEsDTO> list = new ArrayList<>();
        List<UnitToEsDTO> resultlist = new ArrayList<>();
        try{
            // 定义搜索请求和索引
            SearchRequest searchRequest = new SearchRequest(ESConstant.UNIT_GEOGRAPHICAL_POSITION_INDEX);

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // 分页 es好像是没有自带的PageHelp 变成我们所需的分页
            if(unitToEsDTO.getStart()!=null&&unitToEsDTO.getLimit()!=null){
                Integer startPage = (unitToEsDTO.getStart()-1)*unitToEsDTO.getLimit();
                Integer limitPage = unitToEsDTO.getLimit();
                searchSourceBuilder.from(startPage);
                searchSourceBuilder.size(limitPage);
            }

            // 构造查询和过滤数据
            searchSourceBuilder.query(
                    // 构造布尔查询
                    QueryBuilders.boolQuery()
                            // 查询语句
                            .must(
                                    //对type进行过滤 可以在这里筛选一些不需要的
                                    QueryBuilders.matchQuery("type", unitToEsDTO.getType())
                                    //不过滤
                                    //QueryBuilders.matchAllQuery()
                            )
                            // 过滤语句
                            .filter(
                                    // name 是过滤的字段
                                    QueryBuilders.geoDistanceQuery("location")
                                            // 在distance km之内  km  也可以设置为m  cm等
                                            .distance(unitToEsDTO.getDistance(), DistanceUnit.KILOMETERS)
                                            // 以那个点为中心
                                            .geoDistance(GeoDistance.ARC)
                                            // 设置经纬度
                                            .point(unitToEsDTO.getLatitude(), unitToEsDTO.getLongitude())
                            )
            );

            // 排序
            searchSourceBuilder.sort(
                    // 不同的类型使用不同的SortBuilder
                    new GeoDistanceSortBuilder("location", unitToEsDTO.getLatitude(), unitToEsDTO.getLongitude())
                            // 升序
                            .order(SortOrder.ASC)
                            .unit(DistanceUnit.METERS)
                            .geoDistance(GeoDistance.ARC)
            );

            searchRequest.source(searchSourceBuilder);

            SearchResponse search =client.search(searchRequest,RequestOptions.DEFAULT);

            SearchHit[] hits=search.getHits().getHits();
            if(unitToEsDTO.getType()==1||unitToEsDTO.getType()==2){
                for(SearchHit hit: hits){
                    UnitToEsDTO unitToEsDTOResult=JSONObject.parseObject(hit.getSourceAsString(),UnitToEsDTO.class);
                    list.add(unitToEsDTOResult);
                }
                for(UnitToEsDTO unitToEsDTOTemp: list){
                    Long id=Long.parseLong(unitToEsDTOTemp.getId());
                    //去表里查询一下  有的返回没有的不返回 懒得做删除 所以校验了一下
                    UnitExtendEntity unitExtendEntity=unitExtendMapper.selectByExtendId(id);
                    if(!StringUtils.isEmpty(unitExtendEntity)){
                        // 也可以 add unitExtendEntity 看需求
                        resultlist.add(unitToEsDTOTemp);
                    }
                }
            }else {
                log.error("暂无其它类型  看如果有别的也做同样操作");
            }
        }catch(Exception ex){
            log.error("出现异常,参数是{}",JSONObject.toJSONString(unitToEsDTO));
            log.error("出现异常",ex);
        }
        return resultlist;
    }

方法二

好像这个不太准确

 public List<EleTransformer> queryTransformers(String space,String userId,String dataFrom,EleTransformer eleTransformer){
        List<EleTransformer> list = new ArrayList<>();
        List<EleTransformer> resultlist = new ArrayList<>();
        try{

            GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery("location")
                    .distance(eleTransformer.getDistance()).point(new GeoPoint(eleTransformer.getLatitude(), eleTransformer.getLongitude()));
            // 通过SearchSourceBuilder构建搜索参数
            SearchSourceBuilder builder = new SearchSourceBuilder();

            BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
            boolBuilder.must(geoDistanceQueryBuilder);
            builder.query(boolBuilder);

            // 距离sort 排序
            GeoDistanceSortBuilder geoDistanceSortBuilder = SortBuilders.geoDistanceSort("location",
                    new GeoPoint(eleTransformer.getLatitude(), eleTransformer.getLongitude()));
            // 升序排序 距离最近的排在最前面
            geoDistanceSortBuilder.order(SortOrder.ASC);
            // 设置排序参数
            builder.sort(geoDistanceSortBuilder);      
            SearchRequest searchRequest = new SearchRequest(ESConstant.SITE_GEOGRAPHICAL_POSITION_INDEX);
            searchRequest.source(builder);
//            List<EleTransformerDTO> resultList = new ArrayList<>();
            SearchResponse search =client.search(searchRequest,RequestOptions.DEFAULT);
            SearchHit[] hits=search.getHits().getHits();
            for (SearchHit hit : hits) {
                EleTransformer eleTransformers=JSONObject.parseObject(hit.getSourceAsString(),EleTransformer.class);
                list.add(eleTransformers);
            }
            for (EleTransformer ele:list) {
                //去站点表里查询一下  有的返回没有的不返回
                Long siteId =Long.parseLong(ele.getId()) ;
                //判断该站点id是否在库里是否存在
                int siteCou = sxelesiteMapper.querySiteIsExistsById(siteId);
                if (siteCou>0){
                    resultlist.add(ele);
                }
            }
        }catch(Exception ex){
            log.error("出现异常,参数是{}",JSONObject.toJSONString(eleTransformer));
            log.error("出现异常",ex);
        }
        return resultlist;
    }

修改

我这里修改和插入可能是一个接口 所以做了判断

 /**
     *修改
     */
    public void updateToEs(UnitToEsDTO unitToEsDTO){
        try{
            Map<String,Object> stringObjectMap=CopyBeanUtils.bean2Map(unitToEsDTO);

			// 根据类型判断id  如果不是多个type 可以忽略这些
            String esId = unitToEsDTO.getId()+"unknow";

            if(unitToEsDTO.getType()==1){
                esId = unitToEsDTO.getId();
            }else if(unitToEsDTO.getType()==2){
                esId = unitToEsDTO.getId()+"euq";
            }
            // 查询是否存在
            GetRequest request = new GetRequest(ESConstant.UNIT_GEOGRAPHICAL_POSITION_INDEX,esId);
            boolean exists=client.exists(request,RequestOptions.DEFAULT);
            // 存在更新
            if(exists){
            	// 根据id更新
                UpdateRequest updateRequest = new UpdateRequest(ESConstant.UNIT_GEOGRAPHICAL_POSITION_INDEX,esId);
                updateRequest.doc(stringObjectMap,XContentType.JSON);
                client.update(updateRequest,RequestOptions.DEFAULT);
            }else {//不存在插入
                saveToEs(unitToEsDTO);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }

插入

这里的CopyBeanUtils.bean2Map 去文章里找吧 各种utils

   /**
     *插入
     */
    public void saveToEs(UnitToEsDTO unitToEsDTO){
        try{
            Map<String,Object> stringObjectMap=CopyBeanUtils.bean2Map(unitToEsDTO);
            IndexRequest indexRequest = new IndexRequest(ESConstant.UNIT_GEOGRAPHICAL_POSITION_INDEX).source(stringObjectMap,XContentType.JSON);
            //unitToEsDTO的id将作为 es的id插入 方便以后更新
            if(unitToEsDTO.getType()==1){
                indexRequest.id(unitToEsDTO.getId());
            }else if(unitToEsDTO.getType()==2){
                indexRequest.id(unitToEsDTO.getId()+"equ");
            }else {
                indexRequest.id(unitToEsDTO.getId()+"unknow");
            }
            client.index(indexRequest,RequestOptions.DEFAULT);
        }catch(IOException e){
            e.printStackTrace();
        }
    }

删除

DeleteRequest request = new DeleteRequest(
        "index",//索引   
        "doc",  //类型  
        "1"); 	//id
DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT);

踩坑

查询时出现报错信息

org.elasticsearch.ElasticsearchStatusException: Elasticsearch exception [type=search_phase_execution_exception, reason=all shards failed]
	at org.elasticsearch.rest.BytesRestResponse.errorFromXContent(BytesRestResponse.java:177)
	at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:1793)
	at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:1770)
	at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1527)
	at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1484)
	at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1454)
	at org.elasticsearch.client.RestHighLevelClient.search(RestHighLevelClient.java:970)
	at com.qhdsx.apollo.module.msgcenter.es.ESTest.queryTransformers(ESTest.java:503)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
	Suppressed: org.elasticsearch.client.ResponseException: method [POST], host [http://XXX:9200], URI [/test-haina-location_test/_search?pre_filter_shard_size=128&typed_keys=true&max_concurrent_shard_requests=5&ignore_unavailable=false&expand_wildcards=open&allow_no_indices=true&ignore_throttled=true&search_type=query_then_fetch&batched_reduce_size=512&ccs_minimize_roundtrips=true], status line [HTTP/1.1 400 Bad Request]
{"error":{"root_cause":[{"type":"query_shard_exception","reason":"field [location] is not a geo_point field","index_uuid":"iYrfwfgMRLm8ramVz-RbQw","index":"test-haina-location_test"}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":"test-haina-location_test","node":"QWcv79-xTDSp3UHYFQ4AFw","reason":{"type":"query_shard_exception","reason":"field [location] is not a geo_point field","index_uuid":"iYrfwfgMRLm8ramVz-RbQw","index":"test-haina-location_test"}}]},"status":400}
		at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:283)
		at org.elasticsearch.client.RestClient.performRequest(RestClient.java:261)
		at org.elasticsearch.client.RestClient.performRequest(RestClient.java:235)
		at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1514)
		... 28 common frames omitted

详细原因

{
	"error": {
		"root_cause": [{
			"type": "query_shard_exception",
			"reason": "field [location] is not a geo_point field",
			"index_uuid": "iYrfwfgMRLm8ramVz-RbQw",
			"index": "test-haina-location_test"
		}],
		"type": "search_phase_execution_exception",
		"reason": "all shards failed",
		"phase": "query",
		"grouped": true,
		"failed_shards": [{
			"shard": 0,
			"index": "test-haina-location_test",
			"node": "QWcv79-xTDSp3UHYFQ4AFw",
			"reason": {
				"type": "query_shard_exception",
				"reason": "field [location] is not a geo_point field",
				"index_uuid": "iYrfwfgMRLm8ramVz-RbQw",
				"index": "test-haina-location_test"
			}
		}]
	},
	"status": 400
}

在数据插入之前 在kibana控制台 给该索引的location设置一下类型即可

PUT /test-haina-location_test
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
  }
}

如果在数据插入后操作会报异常 可能就得迁移数据了

{
  "error" : {
    "root_cause" : [
      {
        "type" : "resource_already_exists_exception",
        "reason" : "index [test-haina-location_test/iYrfwfgMRLm8ramVz-RbQw] already exists",
        "index_uuid" : "iYrfwfgMRLm8ramVz-RbQw",
        "index" : "test-haina-location_test"
      }
    ],
    "type" : "resource_already_exists_exception",
    "reason" : "index [test-haina-location_test/iYrfwfgMRLm8ramVz-RbQw] already exists",
    "index_uuid" : "iYrfwfgMRLm8ramVz-RbQw",
    "index" : "test-haina-location_test"
  },
  "status" : 400
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值