Spring Data Elasticsearch的@Field注解无效。

16

我有一个Spring Boot应用程序,其中包含pom.xml中的Spring Data Elasticsearch插件。我创建了一个文档类,希望对其进行索引:

@Document(indexName = "operations", type = "operation")
public class OperationDocument {

@Id
private Long id;

@Field(
    type = FieldType.String, 
    index = FieldIndex.analyzed, 
    searchAnalyzer = "standard", 
    indexAnalyzer = "standard",
    store = true
)
private String operationName;

@Field(
    type = FieldType.Date, 
    index = FieldIndex.not_analyzed, 
    store = true, 
    format = DateFormat.custom, pattern = "dd.MM.yyyy hh:mm"
)
private Date dateUp;

@Field(
    type = FieldType.String, 
    index = FieldIndex.not_analyzed, 
    store = false
) 
private String someTransientData;

@Field(type = FieldType.Nested)
private List<Sector> sectors;

//Getter and setters

我也创建了一个该课程的代码库:
 public interface OperationDocumentRepository 
      extends ElasticsearchRepository<OperationDocument, Long> {
 }

我做了一个测试,使用存储库索引了三个示例对象。它相当长,所以只有在必要时才会发布它。事实上,ES服务器中创建的映射忽略了@Field注释设置的配置:

"mappings": {
  "operation": {
    "properties": {
      "operationName": {
        "type": "string"
      },
      "dateUp": {
        "type": "long"
      },
      "someTransientData": {
        "type": "string"
      },
      "sectors": {
        "properties": {
          "id": {
            "type": "long"
          },
          "sectorName": {
            "type": "string"
          }
        }
      }
    }
  }
}

没有有关分析器的信息,"someTransientData"被存储和索引,而dateUp的类型为Long而不是Date。

直接从服务器请求的示例文档:

 {
   "_index": "operations",
   "_type": "operation",
   "_id": "AUyUk2cY3nXeOFxdOlQW",
   "_version": 1,
   "_score": 1,
   "_source": {
     "id": null,
     "operationName": "Second Operation Name",
     "dateUp": 1428421827091,
     "someTransientData": "Do not index or store",
     "sectors": [
       {
         "id": 2,
         "sectorName": "Health Care"
       },
       {
         "id": 3,
         "sectorName": "Construction"
       }
     ]
   }
 }

我还注意到,当我第二次运行应用程序时,在启动时,只有在索引已经存在时才会打印出以下错误消息:
ERROR 19452 --- [main] .d.e.r.s.AbstractElasticsearchRepository : failed to load elasticsearch nodes : org.elasticsearch.index.mapper.MergeMappingException: Merge failed with failures {[mapper [someTransientData] has different index values, mapper [someTransientData] has different tokenize values, mapper [someTransientData] has different index_analyzer, object mapping [sectors] can't be changed from non-nested to nested, mapper [operationName] has different store values, mapper [operationName] has different index_analyzer, mapper [dateUp] of different type, current_type [long], merged_type [date]]}
这是 Spring Data Elasticsearch 的一个 bug 还是我的操作有误?
我尝试了 Spring Boot 提供的稳定版本和 spring-data-elasticsearch 的最新快照版本。我还尝试了插件提供的嵌入式 Elasticsearch 服务器和当前版本的外部服务器,但结果始终相同。
3个回答

19

我终于成功地复制并解决了这个问题。事实上,我在索引和搜索文档时使用的是ElasticTemplate而不是repositories,因为我的业务逻辑更加复杂(使用聚合等功能)。

随后,我删除了未使用的OperationDocumentRepository。看起来,这个repository在启动时需要将类型映射发布到ES服务器。我原本以为只有@Document类就足够了,但事实并非如此。

所以在这里我们有两个选择:

  • 保留OperationDocumentRepository
  • 将这行代码添加到应用程序启动中:

elasticsearchTemplate.putMapping(OperationDocument.class);

我正在使用SpringBoot - SpringData Elasticsearch v4.0.3 == ElasticSearch 7.6.2。遇到了同样的问题,@Field无法解决。我已经使用'IndexOperations indexOps = elasticsearchTemplate.indexOps(Index.class); indexOps.create();'创建了索引。 - SatyaRajC

2
我尝试使用 Spring Data Elasticsearch 示例应用程序复制问题,但根据您的配置,我得到了上面提到的期望结果。
整个代码已经提交到项目中,链接在这里-->link 请查看生成索引并在 Spring 上下文加载时应用映射的 TestCase-->link 这是 TestCase 生成的映射:
  {
  "operations" : {
    "aliases" : { },
    "mappings" : {
      "operation" : {
        "properties" : {
          "dateUp" : {
            "type" : "date",
            "store" : true,
            "format" : "dd.MM.yyyy hh:mm"
          },
          "operationName" : {
            "type" : "string",
            "store" : true,
            "analyzer" : "standard"
          },
          "sectors" : {
            "type" : "nested"
          },
          "someTransientData" : {
            "type" : "string",
            "index" : "not_analyzed"
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "refresh_interval" : "1s",
        "number_of_shards" : "5",
        "store" : {
          "type" : "fs"
        },
        "creation_date" : "1428677234773",
        "number_of_replicas" : "1",
        "version" : {
          "created" : "1040499"
        },
        "uuid" : "-djzLu-IQ0CBs-M6R0-R6Q"
      }
    },
    "warmers" : { }
  }
}

你能不能使用Spring Boot创建类似的示例,使用 https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-data-elasticsearch,并在公共分享上提交?

我测试了你的示例,它可以正常工作。然后我创建了一个新的Spring Boot项目,它也可以正常工作。现在我正在尝试找出是什么导致了我的第一个应用程序出错。如果我找到了,我会更新第一篇帖子。谢谢! - Javier Alvarez
我终于成功地复制并解决了这个问题。我在另一个答案中发布了原因和解决方案。 - Javier Alvarez

1
我也遇到了使用spring-data-elasticsearch时的这个错误,并得到了解决方案。请查看下面的代码注释。 ES禁止在索引创建后更改字段类型,但您可以更改其他属性,如fielddata
  • Spring Data Elasticsearch 3.2.x
  • Elasticsearch 6.8.4
  • Spring Boot 2.2.x

package com.xxxx.xx.es.entity;

import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
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.Mapping;

@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@Document(indexName = "gaming-laptop", indexStoreType = "fs")
@Mapping(mappingPath = "/gaming-laptop-mappings.json")   // use custom json to configure data structure in ES, default spring data won't work although using @Field(type = FieldType.Keyword)
public class GamingLaptop extends BaseEntity {

    @Id
    private String id;

    @Field
    private String cpu;

    @Field(type = FieldType.Keyword)  // this only works in ES 7.6.2+, Spring Data Elasticsearch 4.0.X+
    private String brandName;

    @Field
    private Integer cores;

    @Field
    private Integer threads;

    @Field
    private String coreFrequency;

    @Field
    private String ssd;

    @Field
    private String ram;

    @Field
    private String produceDate;

    @Field
    private Integer version;

    @Field
    private Double price;

    @Field(type = FieldType.Keyword)
    private String description;

}

resources/gaming-laptop-mappings.json

{
    "properties":{
        "_class":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "brandName":{
            "type":"keyword"
        },
        "coreFrequency":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "cores":{
            "type":"long"
        },
        "cpu":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "description":{
            "type":"keyword"
        },
        "gmtCreated":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "gmtModified":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "price":{
            "type":"float"
        },
        "produceDate":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "ram":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "ssd":{
            "type":"text",
            "fields":{
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "threads":{
            "type":"long"
        },
        "version":{
            "type":"long"
        }
    }
}

或者您可以使用rest高级客户端,采用Javier Alvarez的方法进行调整: elasticsearchTemplate.putMapping(OperationDocument.class);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接