省厅位置汇聚添加点线面周边查询

stwzhj
luyya 2025-08-18 11:30:17 +08:00
parent 549e085df8
commit c22bae090e
4 changed files with 89 additions and 52 deletions

View File

@ -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")

View File

@ -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("服务器内部错误");
}
}

View File

@ -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");
}
/**

View File

@ -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;
}