elasticsearch + geo地理位置附近的站点查询

1  这是自己从SQL里查询出来,然后通过logstash 导入数据的方式,然后先创建索引和mapping,再去启动 logstash 服务 得到正确的数据

select id, SITE_NAME , PROVINCE, ADDRESS, LAT , LNG, concat_ws(',',LAT,Lng) as geo from tms_site 查询语句大小写无关

不明确的是,要全部字段定义mapping才行,而这里只需要把经纬度定义成got_point就行。对下面mapping可以自行修改

{
  "mappings": {
    "doc": {
      "properties": {
        "address": {
          "type": "text"
        },
	 "province": {
          "type": "text"
        },
	 "site_name": {
          "type": "text"
        },
	"type": {
          "type": "text"
        }, 
	"lng": {
	 "type": "float"
	 },
	 "lat": {
	 "type": "float"
	 },
	"id": {
          "type": "long"
         },
        "geo": {
          "type": "geo_point"
        },
	"customer_name": {
          "type": "text"
        },
	"user": {
          "type": "text"
        },
	"tel": {
          "type": "float"
        },
	"gmt_created": {
          "type": "date"
        },
	"is_deleted": {
          "type": "integer"
        }
      }
    }
  }
}

按距离查询的代码


查询的代码如下

// 获取附近的人,并且计算每个站点离我多远, 用排序从最小距离开始
	     @Test
	     public void testGetNearbyPeople() {
	    	 double lat=30.381222; double lon=120.106685;
	    	 String index="tms_site_index"; String type="doc";
	         SearchRequestBuilder srb = client.prepareSearch(index).setTypes(type);
	         srb.setFrom(0).setSize(100);//100人
	         GeoDistanceQueryBuilder location1 = QueryBuilders.geoDistanceQuery("geo").point(lat,lon).distance(10,DistanceUnit.KILOMETERS);
	         srb.setPostFilter(location1);
	         // 获取距离多少公里 这个才是获取点与点之间的距离的
	         GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("geo",lat,lon);
	         sort.unit(DistanceUnit.METERS);
	         sort.order(SortOrder.ASC);
	         sort.point(lat,lon);
	         srb.addSort(sort);
	  
	         SearchResponse searchResponse = srb.execute().actionGet();
	         SearchHits hits = searchResponse.getHits();
	         // 搜索耗时
	         Float usetime = searchResponse.getTook().millis() / 1000f;
	         System.out.println("附近的站点(" + hits.getTotalHits() + "个),耗时("+usetime+"秒):");
	         for (SearchHit hit : hits) {
	             String name = (String) hit.getSourceAsMap().get("site_name");
	             String location = (String)hit.getSourceAsMap().get("geo");
	             String[] str = location.split(",");
	             // 获取距离值,并保留两位小数点
	             BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);
	             Map hitMap = hit.getSourceAsMap();//赋值对象共用地址,对象改变原始数据也改变
	             // 在创建MAPPING的时候,属性名的不可为geoDistance。
	             hitMap.put("geoDistance", geoDis.setScale(0, BigDecimal.ROUND_HALF_DOWN));
	             System.out.println(name+"的坐标:"+str[0]+str[1] + " 此站点距离我" + hit.getSourceAsMap().get("geoDistance") + DistanceUnit.METERS.toString());
	         }
	  
	     }

下面是按距离查询附近有多少个站,没计算距离,

	   //取出20公里以内的所有站点,但是不计算距离
	   @Test
	    public void testDistanceQuery() {
	        GeoDistanceQueryBuilder queryBuilder = QueryBuilders.geoDistanceQuery("geo")//location
	            .point(31.32822800, 120.53157000)
	            .distance(20, DistanceUnit.KILOMETERS)
	            .geoDistance(GeoDistance.ARC);//最慢但最精确的是 arc 计算方式
	        SearchResponse response = client.prepareSearch("tms_site_index")
	                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
	                .setQuery(queryBuilder).execute().actionGet();
	        System.out.println(response);
	        System.err.println(response.getHits().getTotalHits());
	        SearchHits hits = response.getHits();
	        for (SearchHit hit : hits) {
	             String name = (String) hit.getSourceAsMap().get("site_name");
	             String address = (String) hit.getSourceAsMap().get("address");
	             String location = (String)hit.getSourceAsMap().get("geo");
	              String[] str = location.split(",");
	             System.out.println(name+"的坐标:"+str[0]+str[1]+ "地址" + address);
	         }
	    	 client.close();
	    	 }

 

下面把一般正常的logstash filter贴下, 以作参考

这是过滤条件,然后指定原始字段,

filter {
      mutate {
	  #取出message消息体的数据,然后用逗号分隔出为再分组
          split => { "message" => "," }
           add_field => {
                "id" => "%{message[1]}"
                "FWYT_s" => "%{message[2]}"
                "lon" => "%{message[3]}"
                "lat" => "%{message[4]}"
                }
          remove_field => [ "message", "host" ]
      }
	  #把数据库的字段改变类型后再写入elasticsearch
      mutate {
          convert => { "lon" => "float" }
          convert => { "lat" => "float" }
      }
      mutate {
          rename => {
              "lon" => "[geo][lon]"
              "lat" => "[geo][lat]"
          }
      }
}

下面是用到的模板定义mapping 也只定义一个,比如  template => "myfile/map_template.json"
  "mappings": {
        "node_points" : {
          "properties" : {
         "geo" : { "type" : "geo_point" }
        }
        }
}

还有其它方式的过滤

#增加要显示的列写入ES里,三种不同方式定义,和改变类型,但是geo_point始终没有改成功
#百分号后面的数就是message消息体的参数
 
 mutate {   //把两个字段合并成一个 "lonlat":["116.39237900","39.91400100"]
   add_field => [ "[lonlat]", "%{lon}" ]
   add_field => [ "[lonlat]", "%{lat}" ]
 }
 
   add_field => {
                "lon" => "%{message[6]}"
                "lat" => "%{message[7]}"
                }
	mutate {
          convert => { "lon" => "float" }
          convert => { "lat" => "float" }
      }
 

实际中用到的更多,写起来确实也费神,慢慢看文档写还能应付日常开发

 

你可能感兴趣的:(elasticsearch)