#java #spring-boot #elasticsearch #spring-data #spring-data-elasticsearch
#java #spring-boot #elasticsearch #spring-data #spring-data-elasticsearch
Вопрос:
в настоящее время мы добавляем в наше приложение spring панель мониторинга с информацией из нашего эластичного. Мы используем документированный подход через RestHighLevelClient .. Запрос и сопоставление работают довольно хорошо. Однако, когда мы попытались добавить несколько дополнительных полей, мы ожидали получить соответствующие значения. Вместо этого мы получили следующую трассировку стека:
java.lang.IllegalArgumentException: null is not a Map.
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$MapValueAccessor.getAsMap(MappingElasticsearchConverter.java:941) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$MapValueAccessor.get(MappingElasticsearchConverter.java:911) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$ElasticsearchPropertyValueProvider.getPropertyValue(MappingElasticsearchConverter.java:956) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.readProperties(MappingElasticsearchConverter.java:266) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.readEntity(MappingElasticsearchConverter.java:197) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.read(MappingElasticsearchConverter.java:177) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.read(MappingElasticsearchConverter.java:77) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate$ReadDocumentCallback.doWith(AbstractElasticsearchTemplate.java:714) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source) ~[na:na]
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) ~[na:na]
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source) ~[na:na]
at org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate$ReadSearchDocumentResponseCallback.doWith(AbstractElasticsearchTemplate.java:738) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate$ReadSearchDocumentResponseCallback.doWith(AbstractElasticsearchTemplate.java:724) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate.search(ElasticsearchRestTemplate.java:276) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery.execute(ElasticsearchPartQuery.java:120) ~[spring-data-elasticsearch-4.1.1.jar!/:4.1.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.4.1.jar!/:2.4.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.4.1.jar!/:2.4.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152) ~[spring-data-commons-2.4.1.jar!/:2.4.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131) ~[spring-data-commons-2.4.1.jar!/:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar!/:5.3.1]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.4.1.jar!/:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar!/:5.3.1]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.1.jar!/:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar!/:5.3.1]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.1.jar!/:5.3.1]
at com.sun.proxy.$Proxy85.findByFooInfo(Unknown Source) ~[na:na]
at org.foo.bar.casper.web.InitialConfigurationDashboardController.getInitialConfigurationDashboardPage(InitialConfigurationDashboardController.java:69) ~[classes!/:0.0.1-191]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:807) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1061) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652) ~[tomcat-embed-core-9.0.39.jar!/:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.1.jar!/:5.3.1]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.39.jar!/:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93) ~[spring-boot-actuator-2.4.0.jar!/:2.4.0]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar!/:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:747) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.39.jar!/:9.0.39]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Новые поля выглядят следующим образом:
package org.foo.bar.casper.datascraping;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Document(indexName = "foo-data")
@NoArgsConstructor
public class ElasticInitialConfiguration {
@Id
@Field(name = "_id")
private String id;
@Field(name = "_meta.isConfigurable.result")
private String configurable;
@Field(name = "_meta.isConfigurable.error.message")
private String errorMessage;
@Field(name = "_meta.configurationContext.fooInfo")
private String fooInfo;
...
}
package org.foo.bar.casper.datascraping;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.domain.Pageable;
public interface DataScrapingRepository extends ElasticsearchRepository<ElasticInitialConfiguration, String> {
Page<ElasticInitialConfiguration> findByFooInfo(String fooInfo, Pageable pageable);
}
package org.foo.bar.casper.datascraping;
import lombok.NoArgsConstructor;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
@Configuration
@NoArgsConstructor
@EnableElasticsearchRepositories(basePackages = "org.foo.bar.casper.datascraping")
public class DatascrapingConfiguration {
@Value("${elastic.username}")
private String user;
@Value("${elastic.password}")
private String password;
@Value("${elastic.url}")
private String url;
@Bean
public RestHighLevelClient client() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(url)
.usingSsl()
.withBasicAuth(user, password)
.build();
return RestClients.create(clientConfiguration).rest();
}
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchRestTemplate(client());
}
}
Новые поля — это те, которые указаны выше info, которые всегда работали. Недавно добавленные значения полей иногда равны нулю, что, по нашему мнению, приводит к исключению.
Мы уже пробовали некоторые исправления, например, добавление @Nullable к полям. Другой добавлял ** @Mapping(mappingPath = «elastic/null_mapping.json») ** со следующим json в разделе resources/elastic:
{
"type": "string",
"index": "analyzed",
"analyzer": "word_analyzer",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed",
"null_value": "NULL"
}
}
}
Однако мы не знаем, верен ли json.
Ошибка кажется довольно необычной. Мы не нашли его в Интернете и не смогли получить хотя бы другой. Поэтому здесь приветствуются любые предложения. Невозможно не получить поля.
Спасибо за ваше время
Комментарии:
1. Проблема возникает из-за имен свойств в Elasticsearch, содержащих точку (
.
). Как выполняется отображение в Elasticsearch для этих свойств? Точечная нотация подразумевает, что данные представляют собой вложенную структуру объекта.2. @P.J.Meisch, спасибо за ваши мысли. Похоже на проблему. Мы довольно новички в elasticsearch. Не могли бы вы указать нам направление, как это сделать?
3. @Всем повезло с этим? Мы сталкиваемся с той же проблемой с полями, содержащими точки.
4. @roadkill простым решением было просто ввести иерархию классов, представляющую точечную структуру. Вместо доступа к foo.bar.baz в документе у нас был класс (POJOs) foo, содержащий bar, имеющий поле baz. Основной @Doucment содержит следующий уровень классов в виде полей и так далее. Надеюсь, это поможет