Java 实体未映射到 ElasticSearch GeoPoint 属性
Posted
技术标签:
【中文标题】Java 实体未映射到 ElasticSearch GeoPoint 属性【英文标题】:Java entity not mapping to ElasticSearch GeoPoint property 【发布时间】:2019-08-27 13:49:06 【问题描述】:我正在开发一个微服务,用于使用 spring-data-elasticsearch 使用 Java/Spring Boot 管理位置,当尝试使用我的控制器向 ES 输入新数据时,数据输入未正确映射到 ES 中的文档,特别是地理点属性“位置”。
我尝试使用来自 import org.springframework.data.elasticsearch.core.geo.GeoPoint 和来自 org.springframework.data.elasticsearch.core.geo.GeoPoint 的 GeoPoint,在这两种情况下都没有输入保存到 ES 的数据作为geo_point
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import io.swagger.annotations.ApiModelProperty;
@Document(indexName = "location", type="location")
public class Location
@Id
@ApiModelProperty(hidden = true)
private String id;
private String appId;
private String resourceId;
@GeoPointField
private GeoPoint location;
private String street;
private String city;
// more attr and method was ommited
使用 ElasticSearchRepository 将数据保存到 ES 后,当我获取映射数据时显示如下:
"location" :
"mappings" :
"location" :
"properties" :
"appId" :
"type" : "text",
"fields" :
"keyword" :
"type" : "keyword",
"ignore_above" : 256
,
"city" :
"type" : "text",
"fields" :
"keyword" :
"type" : "keyword",
"ignore_above" : 256
,
"country" :
"properties" :
"countryCcFips" :
"type" : "text",
"fields" :
"keyword" :
"type" : "keyword",
"ignore_above" : 256
,
"countryCcIso" :
"type" : "text",
"fields" :
"keyword" :
"type" : "keyword",
"ignore_above" : 256
,
"countryName" :
"type" : "text",
"fields" :
"keyword" :
"type" : "keyword",
"ignore_above" : 256
,
"location" :
"properties" :
"lat" :
"type" : "float"
,
"lon" :
"type" : "float"
,
"parish" :
"type" : "text",
"fields" :
"keyword" :
"type" : "keyword",
"ignore_above" : 256
// ommited more json data
请,我需要将 GeoPoint 字段(位置)映射到 ES 中的 geo_point,这对于正确执行 Geoqueries 很重要。
我使用 Spring Data ElasticSearch,使用 Spring Boot 2.1.3.RELEASE 和 ElasticSearch driver 6.4.3,使用 ElasticSearch server 6.4
【问题讨论】:
这确实很奇怪,我刚刚检查了代码,通常您只需要拥有GeoPoint
类或GeoPointField
注释即可将字段键入为“geo_point”。代码中的这个位置多年来一直没有改变。我将尝试用本地示例重现这一点,但不能保证我今天会找到时间。
【参考方案1】:
我创建了一个带有存储库、控制器的最小应用程序,并使用 Spring Boot 2.1.3.RELEASE、Spring Data Elasticsearch 3.1.5.RELEASE、elasticsearch 客户端 6.4.3 和 Elasticsearch 服务器 6.4.0 运行它。
我正在使用一个 Person
pojo 类,它有两个 geo_point 字段,一个是普通的 spring GeoPoint
,另一个是使用 GeoPointField
annotation 的自定义 MyGeoPoint
。
启动应用并调用RestController的init
方法插入记录后,索引中的映射就可以了:
"person":
"aliases": ,
"mappings":
"person":
"properties":
"firstName":
"type": "text",
"fields":
"keyword":
"type": "keyword",
"ignore_above": 256
,
"geoPoint":
"type": "geo_point"
,
"id":
"type": "long"
,
"lastName":
"type": "text",
"fields":
"keyword":
"type": "keyword",
"ignore_above": 256
,
"myGeoPoint":
"type": "geo_point"
,
"settings":
"index":
"refresh_interval": "1s",
"number_of_shards": "5",
"provided_name": "person",
"creation_date": "1554750620775",
"store":
"type": "fs"
,
"number_of_replicas": "1",
"uuid": "w1L279wOQUmvDPMu4iYXtg",
"version":
"created": "6040099"
Person.java
/*
* (c) Copyright 2019 sothawo
*/
package com.sothawo.springdataelastictest;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
/**
* @author P.J. Meisch (pj.meisch@sothawo.com)
*/
@Document(indexName = "person", type = "person")
public class Person
@Id private Long id;
private String lastName;
private String firstName;
private GeoPoint geoPoint;
@GeoPointField private MyGeoPoint myGeoPoint;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getLastName()
return lastName;
public void setLastName(String lastName)
this.lastName = lastName;
public String getFirstName()
return firstName;
public void setFirstName(String firstName)
this.firstName = firstName;
public GeoPoint getGeoPoint()
return geoPoint;
public void setGeoPoint(GeoPoint geoPoint)
this.geoPoint = geoPoint;
public MyGeoPoint getMyGeoPoint()
return myGeoPoint;
public void setMyGeoPoint(MyGeoPoint myGeoPoint)
this.myGeoPoint = myGeoPoint;
@Override
public String toString()
return "Person" +
"id=" + id +
", lastName='" + lastName + '\'' +
", firstName='" + firstName + '\'' +
", geoPoint=" + geoPoint +
", myGeoPoint=" + myGeoPoint +
'';
public static class MyGeoPoint
private double lat;
private double lon;
public double getLat()
return lat;
public void setLat(double lat)
this.lat = lat;
public double getLon()
return lon;
public void setLon(double lon)
this.lon = lon;
@Override
public String toString()
return "MyGeoPoint" + "lat=" + lat + ", lon=" + lon + '';
PersonRepository.java:
package com.sothawo.springdataelastictest;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface PersonRepository extends ElasticsearchRepository<Person, Long>
ElasticsearchRepositoryController.java:
package com.sothawo.springdataelastictest;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/repo")
public class ElasticsearchRepositoryController
private PersonRepository personRepository;
public ElasticsearchRepositoryController(PersonRepository personRepository)
this.personRepository = personRepository;
@GetMapping("/init")
public Long initPerson()
final Person person = new Person();
person.setId(42L);
person.setFirstName("John");
person.setLastName("Doe");
GeoPoint geoPoint = new GeoPoint(12.34, 56.78);
person.setGeoPoint(geoPoint);
Person.MyGeoPoint myGeoPoint = new Person.MyGeoPoint();
myGeoPoint.setLat(43.21);
myGeoPoint.setLon(87.65);
person.setMyGeoPoint(myGeoPoint);
return personRepository.save(person).getId();
SpringdataElasticTestApplication.java:
package com.sothawo.springdataelastictest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
@SpringBootApplication
@EnableElasticsearchRepositories
public class SpringdataElasticTestApplication
public static void main(String[] args)
SpringApplication.run(SpringdataElasticTestApplication.class, args);
所以我找不到此代码和我使用的版本的问题。您能否使用这些类重现错误或构建一个重现错误的最小示例?
您确定映射是由 Repository 类而不是其他地方创建的吗?
您能否检查一下映射之后应用程序启动,但之前任何数据插入索引?
【讨论】:
您是如何创建索引的?对我来说,它以一种没有 geo_point 的方式创建!! 如果索引不存在会在启动时自动创建 我发现对于 Geo Point,动态映射不起作用,必须手动完成或通过代码强制执行。另外,我尝试了您提供的指定版本的解决方案,但没有解决问题。【参考方案2】:在应用程序运行时(spring-boot
2.2.1.RELEASE
和spring-data-elasticserach
4.0.0.DATAES-690-SNAPSHOT
)删除索引后,我遇到了同样的问题。
保存文档后,位置属性的索引错误映射:
... other properites...
"location" :
"properties" :
"lat" :
"type" : "float"
,
"lon" :
"type" : "float"
在应用程序运行时无法解决,映射总是错误的。
这个解决方案对我有用:
-
删除索引
重新启动应用程序
现在索引是用 JUST 位置字段创建的,所有其他字段映射都丢失了。索引文档后(使用ElasticSearchRepository.save
),一切都很好,添加了其他映射。
"properties":
"location":
"type": "geo_point"
【讨论】:
【参考方案3】:我遇到了类似的问题,但我是这样解决的: 在 ES 端,像这样创建索引:
PUT my_index
"mappings":
"properties":
"doc.location":
"type": "geo_point"
在location
中是我想成为geo_point 类型的字段。原谅我的英语。
当然,ES 的持久化必须遵循以下结构:
"location":
"lat": 41.12,
"lon": -71.34
你说过here。
【讨论】:
解释你的答案。【参考方案4】:我遇到了类似的问题,但在浏览了一些文档后,我不得不使用以下代码 sn-p 让 Elasticsearch 将我的 GeoPoint
属性创建为 geo_point
类型字段。
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@PostConstruct
public void init()
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(PropertySearch.class);
indexOperations.putMapping(indexOperations.createMapping());
indexOperations.refresh();
更多信息可以参考post
【讨论】:
【参考方案5】:if (elasticsearchRestTemplate.indexOps(MerchantModel.class).exists())
elasticsearchRestTemplate.indexOps(MerchantModel.class).delete();
// fix geo_point mapping
CreateIndexRequest createIndexRequest = new CreateIndexRequest("merchant");
createIndexRequest.mapping("\n" +
" \"properties\": \n" +
" \"location\": \n" +
" \"type\": \"geo_point\"\n" +
" \n" +
" \n" +
" ", XContentType.JSON);
IndicesClient indicesClient = restHighLevelClient.indices();
CreateIndexResponse createIndexResponse = indicesClient.create(createIndexRequest, RequestOptions.DEFAULT);
log.info("create ES merchant mapping:[isAcknowledged=]", createIndexResponse.isAcknowledged());
【讨论】:
请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。以上是关于Java 实体未映射到 ElasticSearch GeoPoint 属性的主要内容,如果未能解决你的问题,请参考以下文章
java使用elasticsearch进行模糊查询之must使用