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" }
}
实际中用到的更多,写起来确实也费神,慢慢看文档写还能应付日常开发