省厅位置汇聚添加点线面周边查询
parent
549e085df8
commit
c22bae090e
|
|
@ -349,7 +349,7 @@ public class GpsServiceImpl implements IGpsService {
|
|||
.field("type", "text")
|
||||
.endObject()
|
||||
.startObject("deviceCode")
|
||||
.field("type", "text")
|
||||
.field("type", "keyword")
|
||||
.endObject()
|
||||
.startObject("infoSource")
|
||||
.field("type", "text")
|
||||
|
|
|
|||
|
|
@ -62,26 +62,15 @@ public class ElasticSearchController extends BaseController {
|
|||
// 1. 构建空间查询
|
||||
QueryBuilder spatialQuery = geoQueryService.buildSpatialQuery(request);
|
||||
|
||||
// 2. 添加时间范围过滤
|
||||
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
|
||||
.filter(spatialQuery);
|
||||
|
||||
if (request.getStartTime() != null && request.getEndTime() != null) {
|
||||
boolQuery.filter(QueryBuilders.rangeQuery("gpsTime")
|
||||
.gte(request.getStartTime())
|
||||
.lte(request.getEndTime()));
|
||||
}
|
||||
|
||||
// 3. 执行轨迹查询(按设备去重)
|
||||
List<EsGpsInfoVO2> results = searchService.queryDistinctDevicesNearPoint(boolQuery,todayIndexName);
|
||||
List<EsGpsInfoVO2> results = searchService.queryDistinctDevicesNearPoint(spatialQuery,todayIndexName);
|
||||
|
||||
// 4. 构建响应
|
||||
|
||||
return R.ok(results);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
return R.fail(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return R.fail("服务器内部错误");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.dromara.location.service.impl;
|
||||
|
||||
import org.dromara.location.domain.SpatialQueryRequest;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.*;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
|
|
@ -36,10 +37,16 @@ public class CorrectGeoQueryService {
|
|||
if (request.getCenter() == null || request.getRadius() == null) {
|
||||
throw new IllegalArgumentException("点查询需要center和radius参数");
|
||||
}
|
||||
String distance = request.getRadius() + request.getUnit().toString().toLowerCase().charAt(0) +"";
|
||||
// 使用GeoPoint确保正确顺序
|
||||
GeoPoint point = new GeoPoint(
|
||||
request.getCenter().getLat(), // 纬度
|
||||
request.getCenter().getLon() // 经度
|
||||
);
|
||||
|
||||
return QueryBuilders.geoDistanceQuery("location")
|
||||
.point(request.getCenter().getLat(), request.getCenter().getLon())
|
||||
.distance(request.getRadius(), request.getUnit().getEsUnit());
|
||||
.point(point)
|
||||
.distance("3km");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import cn.hutool.core.date.DateField;
|
|||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.location.domain.EsGpsInfoVO2;
|
||||
import org.dromara.location.service.ISearchService;
|
||||
import org.elasticsearch.action.search.*;
|
||||
|
|
@ -28,6 +29,10 @@ import org.springframework.stereotype.Service;
|
|||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
|
@ -38,6 +43,7 @@ import java.util.function.Consumer;
|
|||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class SearchServiceImpl implements ISearchService {
|
||||
|
||||
@Resource(name = "restHighLevelClient")
|
||||
|
|
@ -151,51 +157,86 @@ public class SearchServiceImpl implements ISearchService {
|
|||
* @param indexName 索引名称
|
||||
* @return 去重后的设备列表(每个设备只返回最新的一条记录)
|
||||
*/
|
||||
public List<EsGpsInfoVO2> queryDistinctDevicesNearPoint(QueryBuilder spatialQuery, String indexName) throws IOException {
|
||||
|
||||
// 构建聚合
|
||||
TermsAggregationBuilder aggregation = AggregationBuilders.terms("distinct_devices")
|
||||
.field("deviceCode.keyword")
|
||||
.size(100)
|
||||
.subAggregation(
|
||||
AggregationBuilders.topHits("latest_record")
|
||||
.size(1)
|
||||
.sort("gpsTime", SortOrder.DESC)
|
||||
);
|
||||
|
||||
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
|
||||
.query(spatialQuery)
|
||||
.aggregation(aggregation)
|
||||
.size(0);
|
||||
|
||||
SearchRequest request = new SearchRequest(indexName)
|
||||
.source(sourceBuilder);
|
||||
|
||||
// 4. 执行查询
|
||||
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
|
||||
|
||||
// 5. 解析聚合结果
|
||||
Terms terms = response.getAggregations().get("distinct_devices");
|
||||
public List<EsGpsInfoVO2> queryDistinctDevicesNearPoint(QueryBuilder spatialQuery, String indexName) {
|
||||
log.info("Final ES query: {},index={}", spatialQuery.toString(),indexName);
|
||||
List<EsGpsInfoVO2> results = new ArrayList<>();
|
||||
try {
|
||||
// 构建聚合
|
||||
TermsAggregationBuilder aggregation = AggregationBuilders.terms("distinct_devices")
|
||||
.field("deviceCode")
|
||||
.size(50)
|
||||
.shardSize(1000)
|
||||
.subAggregation(
|
||||
AggregationBuilders.topHits("latest_record")
|
||||
.size(1)
|
||||
.sort("gpsTime", SortOrder.DESC)
|
||||
);
|
||||
|
||||
for (Terms.Bucket bucket : terms.getBuckets()) {
|
||||
String deviceCode = bucket.getKeyAsString();
|
||||
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
|
||||
.query(spatialQuery)
|
||||
.aggregation(aggregation)
|
||||
.size(0);
|
||||
|
||||
// 获取每个设备的最新记录
|
||||
TopHits topHits = bucket.getAggregations().get("latest_record");
|
||||
SearchHit[] hits = topHits.getHits().getHits();
|
||||
SearchRequest request = new SearchRequest(indexName)
|
||||
.source(sourceBuilder);
|
||||
|
||||
if (hits.length > 0) {
|
||||
SearchHit latestHit = hits[0];
|
||||
Map<String, Object> source = latestHit.getSourceAsMap();
|
||||
// 4. 执行查询
|
||||
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
|
||||
|
||||
EsGpsInfoVO2 gpsInfoVO2 = BeanUtil.copyProperties(source, EsGpsInfoVO2.class);
|
||||
// 5. 解析聚合结果
|
||||
Terms terms = response.getAggregations().get("distinct_devices");
|
||||
log.info("ES response buckets: {}",terms.getBuckets().size());
|
||||
|
||||
results.add(gpsInfoVO2);
|
||||
|
||||
for (Terms.Bucket bucket : terms.getBuckets()) {
|
||||
String deviceCode = bucket.getKeyAsString();
|
||||
|
||||
// 获取每个设备的最新记录
|
||||
TopHits topHits = bucket.getAggregations().get("latest_record");
|
||||
|
||||
SearchHit[] hits = topHits.getHits().getHits();
|
||||
|
||||
if (hits.length > 0) {
|
||||
SearchHit latestHit = hits[0];
|
||||
Map<String, Object> source = latestHit.getSourceAsMap();
|
||||
// 解析位置信息
|
||||
List<Double> location = (List<Double>) source.get("location");
|
||||
double lon = location.get(0);
|
||||
double lat = location.get(1);
|
||||
EsGpsInfoVO2 gpsInfoVO2 = new EsGpsInfoVO2();
|
||||
gpsInfoVO2.setDeviceCode(deviceCode);
|
||||
gpsInfoVO2.setDeviceType(source.get("deviceType").toString());
|
||||
long timestamp = Instant.parse(source.get("gpsTime").toString()).toEpochMilli();
|
||||
String isoString =source.get("gpsTime").toString();
|
||||
Instant instant = Instant.parse(isoString);
|
||||
Date utcDate = Date.from(instant);
|
||||
|
||||
// 方法2:使用 Hutool + 时区转换
|
||||
Date date = DateUtil.parse(isoString);
|
||||
// 将时间调整为 UTC 时区
|
||||
ZonedDateTime utcZdt = date.toInstant().atZone(ZoneId.of("UTC"));
|
||||
Date utcDate2 = Date.from(utcZdt.toInstant());
|
||||
|
||||
// 验证结果
|
||||
log.error("原始 UTC 时间: " + isoString);
|
||||
log.error("方法1转换结果: " + utcDate);
|
||||
log.error("方法2转换结果: " + utcDate2);
|
||||
log.error("时间戳: " + utcDate.getTime());
|
||||
|
||||
gpsInfoVO2.setGpsTime(new Date(timestamp));
|
||||
gpsInfoVO2.setLat(lat+"");
|
||||
gpsInfoVO2.setLng(lon+"");
|
||||
log.info("gpsInfoVO2={}",gpsInfoVO2.toString());
|
||||
results.add(gpsInfoVO2);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return results;
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue