【问题标题】:Java entity not mapping to ElasticSearch GeoPoint propertyJava 实体未映射到 ElasticSearch GeoPoint 属性
【发布时间】: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”。代码中的这个位置多年来一直没有改变。我将尝试用本地示例重现这一点,但不能保证我今天会找到时间。

标签: java elasticsearch geo spring-data-elasticsearch


【解决方案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,另一个是使用 GeoPointFieldannotation 的自定义 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-boot2.2.1.RELEASEspring-data-elasticserach4.0.0.DATAES-690-SNAPSHOT)删除索引后,我遇到了同样的问题。

保存文档后,位置属性的索引错误映射

... other properites...

"location" : {
  "properties" : {
    "lat" : {
      "type" : "float"
    },
    "lon" : {
      "type" : "float"
    }
  }
}

在应用程序运行时无法解决,映射总是错误的。

这个解决方案对我有用:

  1. 删除索引
  2. 重新启动应用程序

现在索引是用 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());
      

      【讨论】:

      • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
      猜你喜欢
      • 2012-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      • 2013-04-15
      • 2015-01-22
      相关资源
      最近更新 更多