ElasticSearch查询结果转换实体类时出现问题

397 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

近期在工作中需要使用es进行简单的全文检索,所以最近都在边学边做笔记,也会把自己遇到的bug以及如何解决的,一并记录在这里,供大家学习参考。

问题描述

索引结构定义:

{
  "test_xxx" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        ...,
        "xxx1Doc" : {
          "type" : "nested",
          "properties" : {
            "xxxName" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "xxxValue" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              },
              "analyzer" : "ik_max_word",
              "search_analyzer" : "ik_smart"
            }
          }
        },
        ...,
        "xxx2Doc" : {
          "type" : "nested",
          "properties" : {
            "xxxName" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "xxxValue" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              },
              "analyzer" : "ik_max_word",
              "search_analyzer" : "ik_smart"
            }
          }
        }
      }
    }
  }
}

在项目中有对应多个xxxDoc这种类型的字段,通过kibana使用put语句进行赋值,语句如下:

PUT test_xx/_doc/1
{
    ...,
    "xxx1Doc": [{     
        "xxxName": "xxx",
        "xxxValue": "xxx"
    },{
        "xxxName": "xxx",
        "xxxValue": "xxx"
    }],
    "xxx2Doc": {}     
}

代码中的实体类定义如下:

@Document(indexName = "test_xxx")
public class Entity implements Serializable {
    @Id
    private String Id;
    ...
    private List<XXXEntity> xxx1Doc;
    private List<XXXEntity> xxx2Doc;
    private List<XXXEntity> xxx2Doc;
    private List<XXXEntity> xxx2Doc;
    private List<XXXEntity> xxx2Doc;
    ...

service层:

query.withQuery(boolQueryBuilder);
SearchHits<Entity> result = elasticsearchRestTemplate.search(query.build(), Entity.class);

报错内容:

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate java.util.List using constructor NO_CONSTRUCTOR with arguments\
at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:65) ~[spring-data-commons-2.3.9.RELEASE.jar:2.3.9.RELEASE]\
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:87) ~[spring-data-commons-2.3.9.RELEASE.jar:2.3.9.RELEASE]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.readEntity(MappingElasticsearchConverter.java:325) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.read(MappingElasticsearchConverter.java:262) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.readValue(MappingElasticsearchConverter.java:463) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.readValue(MappingElasticsearchConverter.java:447) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader$ElasticsearchPropertyValueProvider.getPropertyValue(MappingElasticsearchConverter.java:634) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.readProperties(MappingElasticsearchConverter.java:409) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.readEntity(MappingElasticsearchConverter.java:332) ~[spring-data-elasticsearch-4.3.4.jar:4.3.4]\
...
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.List]: Specified class is an interface\
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:136) ~[spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]\
at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:62) ~[spring-data-commons-2.3.9.RELEASE.jar:2.3.9.RELEASE]\
... 77 more

问题分析

单目调试拿到搜索语句,在kibana中进行测试,正常返回结果,那说明搜索语句没有问题。

看报错提示貌似是因为我定义的实体类和索引中的类型没有匹配,我一度以为是nested类型的数组形式,不能通过list集合这样去定义,花了一天的时间都在搜代码中应该怎么样去定义,尝试过很多方法,都不能解决这个问题。

因为以doc结尾的字段有很多,想着先只留两个试试,结果发现,哎!!!成功返回了竟然。接下来就是一个字段一个字段的去排除问题,后来发现,当我查询所有数据时,有些字段返回结果是这样的:

"xxxDoc" : { },
"xxxDoc" : { },
"xxxDoc" : { },
"xxxDoc" : { },

好像知道问题在哪里了,虽然我在创建索引的时候,有去设置字段的信息,不过put数据的时候,有些字段我是这样放值的:

"xxx2Doc": {}     

我往里面放了一个空的数据!!!

解决方案

现在知道问题出在哪里了,搜索语句,实体类的定义都没有问题,就是我的put语句,有些时候我们可能不会往某些字段去存值,在put语句中,就可以直接不写那个字段,而不是像我这样去做。

修改好数据之后,问题就都解决啦!!!😊