springboot在集成ES,存储空间数据jts的geometry数据类型,存进es后如何根据点坐标检索对应矢量数据,
检索到数据后将返回值映射成实体的时候报错了,如何解决
实体:
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Polygon;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import javax.persistence.Id;
import java.util.Date;
@Data
@Document(indexName = "geojson")
public class Geojson {
@Id
@Field(type = FieldType.Long)
private Long id;
@Field(type = FieldType.Long)
private Long fileId;
@Field(type = FieldType.Object)
@JsonDeserialize(using = GeometryDeserializer.class)
private Geometry json;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8",locale = "zh_CN")
@Field(type = FieldType.Date, name = "create_time", pattern = "yyyy-MM-dd HH:mm:ss",format = DateFormat.custom )
private Date createTime;
}
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withFilter(queryBuilder)
.withPageable(PageRequest.of(0, 10))
.build();
SearchHits<Geojson> search = elasticsearchRestTemplate.search(query, Geojson.class);
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.locationtech.jts.geom.Polygon]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.locationtech.jts.geom.Polygon.()
你的实体类有问题,json字段的类型为Geometry,而Geometry是一个接口,没有默认的构造函数,所以在映射时无法实例化Geometry的具体实现类
你要么就改成具体的实现类,比如Polygon,Point,LineString
要么就用Spring Data Elasticsearch的自定义映射功能,并且配置合适的序列化和反序列化类来处理Geometry类型
采用chatgpt:
您遇到的错误与 JTS 库中的 Polygon 类没有默认构造函数有关。 这意味着 Elasticsearch 在从检索到的文档映射回数据时无法创建 Polygon 类的实例。
要解决此问题,您可以尝试使用自定义转换器来处理 Geojson 实体中 Geometry 字段的映射。 该转换器将处理 Geometry 对象的序列化和反序列化为 Elasticsearch 可以理解的格式。
以下是如何为几何字段实现自定义转换器的示例:
创建自定义转换器:
import org.locationtech.jts.geom.Geometry;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
@ReadingConverter
@WritingConverter
public class GeometryConverter implements Converter<String, Geometry> {
private final WKTReader wktReader = new WKTReader();
@Override
public Geometry convert(String source) {
try {
return wktReader.read(source);
} catch (ParseException e) {
throw new IllegalArgumentException("Invalid geometry format: " + source, e);
}
}
}
使用 Elasticsearch 映射注册转换器:
import org.locationtech.jts.geom.Geometry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
@Configuration
@EnableElasticsearchRepositories(basePackages = "your.repository.package")
public class ElasticsearchConfig {
@Bean
public ElasticsearchCustomConversions elasticsearchCustomConversions() {
return new ElasticsearchCustomConversions(Arrays.asList(new GeometryConverter()));
}
}
确保将 your.repository.package 替换为 Elasticsearch 存储库类所在的实际包。
通过此设置,GeometryConverter 将处理 Geometry 字段与众所周知的文本 (WKT) 格式(几何对象的文本表示形式)之间的序列化和反序列化。 Elasticsearch 会将几何图形存储为 WKT 格式的字符串,自定义转换器在检索数据时会将其转换回 Geometry 对象。
这应该可以解决与缺少 Polygon 默认构造函数相关的 BeanInstantiationException 错误。
报错信息指出缺少Polygon的默认构造函数。为了解决这个问题,你需要为Polygon类添加一个默认构造函数。
在Geojson实体类中添加以下代码:
java
import org.locationtech.jts.geom.Polygon;
public class Polygon extends Polygon {
public Polygon() {
super(null, null);
}
}
这样,你就为Polygon类添加了默认构造函数,解决了报错问题。
注意:由于你使用的是自定义的Polygon类和默认的Polygon类同名,可能会导致冲突。为了避免冲突,你可以将自定义的Polygon类命名为其他名称,例如CustomPolygon。
"json": {
"_class": "org.locationtech.jts.geom.Polygon",
"shell": {
"points": {
"_class": "org.locationtech.jts.geom.impl.CoordinateArraySequence",
"dimension": 3,
"measures": 0,
"coordinates": [
{
"x": 121.2583329,
"y": 28.6553629,
"z": "NaN"
},
{
"x": 121.2583329,
"y": 28.4375079,
"z": "NaN"
},
{
"x": 121.6972175,
"y": 28.4375079,
"z": "NaN"
},
{
"x": 121.6972175,
"y": 28.6553629,
"z": "NaN"
},
{
"x": 121.2583329,
"y": 28.6553629,
"z": "NaN"
}
]
},
"factory": {
"precisionModel": {
"modelType": {
"name": "FLOATING"
},
"scale": 0.0
},
"coordinateSequenceFactory": {
"_class": "org.locationtech.jts.geom.impl.CoordinateArraySequenceFactory"
},
"SRID": 0
},
"SRID": 0
},
"holes": [],
"factory": {
"precisionModel": {
"modelType": {
"name": "FLOATING"
},
"scale": 0.0
},
"coordinateSequenceFactory": {
"_class": "org.locationtech.jts.geom.impl.CoordinateArraySequenceFactory"
},
"SRID": 0
},
"SRID": 0
}
这是ES存的json数据,反序列化这个json会出错
在反序列化的时候可以debug看一下他的类是长什么样的,他是怎么反序列化的。他是哪里出了问题,
我觉得这种应该去看一下官方文档怎么做的
参考gpt:
结合自己分析给你如下建议:
这是一个比较复杂的问题,可能涉及到多个方面的原因和解决方法。我尝试从以下几个方面来回答您:
存储jts的geometry数据类型到ES中。这需要将jts的geometry数据类型转换为ES支持的geo_shape数据类型,或者使用GeoJSON或WKT格式来表示geometry数据。ES的geo_shape数据类型可以支持多种几何形状,如点、线、多边形等,并且可以进行空间查询和聚合。GeoJSON和WKT是两种常用的几何对象表示格式,它们可以与jts的geometry数据类型相互转换。您可以使用一些工具类或者库来进行这些转换,例如org.locationtech.jts.io.WKTReader和WKTWriter,或者https://github.com/bedatadriven/jackson-datatype-jts。
根据点坐标检索对应矢量数据。这需要使用ES的geo_shape查询来根据点坐标来过滤出与之相交或者包含的矢量数据。您可以使用QueryBuilders.geoShapeQuery方法来构建一个GeoShapeQueryBuilder对象,并指定点坐标和关系类型(如intersects或within)。然后您可以使用ElasticsearchRestTemplate.search方法来执行查询,并得到SearchHits对象。
将返回值映射成实体。这需要使用jackson-datatype-jts库来实现jts的geometry数据类型和GeoJSON格式之间的序列化和反序列化。您可以在实体类中使用@JsonDeserialize(using = GeometryDeserializer.class)注解来指定反序列化器,或者在配置类中使用@Bean注解来注册JtsModule到ObjectMapper中。