1. 创建geo_point类型字段映射:
PUT test
{
"mappings": {
"user": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
}
ES比较明显的缺点:字段类型无法修改、写入性能较低和高硬件资源消耗。
1. ES会自动建立索引,ES需要在创建字段前要预先建立Mapping,Mapping中包含每个字段的类型信息,ES需要根据Mapping为字段建立合适的索引。
2. 由于这个Mapping的存在,ES中的字段一但建立就不能再修改类型了。也就是说:如果已经在已经有数据,想改变字段类型,可能要全部删除,重新导入数据。
3. 自动建立索引使得ES的写入性能也收到了影响,并且ES的写入有默认1S的写入延迟。
4. 建立复杂的索引占用空间,对硬件资源的消耗也是非常厉害。
2. 加入依赖:
使用spring-data-elasticsearch依赖
<!-- ElasticSearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
3. 创建Doc文档对象:
package cn.nagisa.geo.doc;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
/**
* @author nagisa
*/
@Data
@Document(indexName = "test",type = "user")
public class UserDoc {
private Long id;
private String username;
@GeoPointField
private GeoPoint location;
}
这里的Doc相当于entity,注意加上@GeoPointField,表示localcation是Es当中geo_point类型的字段。
4. 创建Repository:
/**
* @author nagisa
*/
@Repository
public interface UserRepository extends ElasticsearchRepository<UserDoc,Long> {
}
继承ElasticsearchRepository,泛型当中的Long相当于主键的类型。
5. 查询实现:
Service的实现:
/**
* @param lat 区域中心的经度
* @param lng 区域中心纬度
* @param distance 区域半径
* @return 符合条件的数据
*/
@Override
public JsonResult fixedArea(Double lat, Double lng, Integer distance) {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
// 以某点为中心,搜索指定范围
GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location");
distanceQueryBuilder
.point(lat, lng)
.distance(distance, DistanceUnit.KILOMETERS);
boolQueryBuilder.filter(distanceQueryBuilder);
//查询封装
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
NativeSearchQuery build = nativeSearchQueryBuilder
.withQuery(boolQueryBuilder)
.build();
return JsonResult.me().setResult(userRepository.search(build));
}
Controller的实现:
/**
* @param lat 区域中心的经度
* @param lng 区域中心纬度
* @param distance 区域半径
* @return 符合条件的数据
*/
@GetMapping("/fixedArea")
public JsonResult fixedArea(Double lat,Double lng,Integer distance){
return userEsService.fixedArea(lat,lng,distance);
}
6. 错误排查:
Error: all shards failed
可能原因:经纬度调换,传反了。
7. 扩展:Mysql 8当中的空间函数:
MySQL空间函数ST_Distance_Sphere(g1, g2 [, radius]) :返回球体上两个点和/或多点之间的最小球面距离(以米为单位)
如:
st_distance_sphere(point(#{ll.lon},#{ll.lat}),point(lon,lat)) < #{radius}
radius表示指定距离