SpringBoot 集成 elasticsearch 7.x和对应版本不一致异常信息处理

news/2024/11/29 18:45:42/

开源框架springboot框架中集成es。使用org.springframework.data.elasticsearch下的依赖,实现对elasticsearch的CURD,非常方便,但是springboot和elasticsearch版本对应很严格,对应版本不统一启动会报错。

文章目录

    • 开源框架
    • Elasticsearch 7.x安装
    • Elasticsearch和springboot版本对应
    • 配置elasticSearch
    • 测试类
    • springframework实现对象操作es
      • es实体对象
      • es接口
      • AbstractResultMapper
      • Mapper
      • Service
      • ServiceImpl

开源框架

开源框架
在这里插入图片描述

Elasticsearch 7.x安装

Elasticsearch 7.x 安装步骤

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

注意:
springboot集成的elasticSearch的版本可能和
我们自己使用的不一致,可能会导致项目报错,需要手动把版本
改成和我们使用的一致

版本不一致异常信息:
在这里插入图片描述

Elasticsearch和springboot版本对应

Elasticsearch和springboot版本对应

springboot 2.1.6 对应 Elasticsearch 6.3.2
springboot 2.2.5 对应 Elasticsearch 7.6.0
springboot 2.2.6 对应 Elasticsearch 7.7.0

配置elasticSearch

@Configuration
public class ESClient {@Beanpublic RestHighLevelClient restHighLevelClient(){RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1",9200,"http")));return client;}
}

测试类

@SpringBootTest
class EstestApplicationTests {@Autowired@Qualifier("restHighLevelClient")private RestHighLevelClient client;//测试创建索引库@Testvoid createIndex() throws IOException {//创建请求CreateIndexRequest request = new CreateIndexRequest("test1");//执行请求CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);System.out.println(response.toString());//org.elasticsearch.client.indices.CreateIndexResponse@6a5dc7e}//查看索引库是否存在 true存在,false不存在@Testvoid existsIndex() throws IOException {//创建请求GetIndexRequest request = new GetIndexRequest("test1");boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println(exists);}//删除索引库@Testvoid deleteIndex() throws IOException {DeleteIndexRequest request = new DeleteIndexRequest("test1");AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);//删除成功返回true,失败返回falseSystem.out.println(delete.isAcknowledged());}//文档操作================================================================================//添加文档@Testvoid createDocument() throws IOException {//创建添加数据User user = new User("张三",23);//声明要保存到那个索引库IndexRequest request = new IndexRequest("test1");request.id("1").timeout("1s");//给请求放入数据request.source(JSON.toJSONString(user), XContentType.JSON);//执行请求IndexResponse resp = client.index(request, RequestOptions.DEFAULT);System.out.println(resp);System.out.println(resp.status());//CREATED}//修改文档@Testvoid updateDocument() throws IOException {//声明修改数据//User user = new User("李四",20);User user = new User();user.setName("王五");//声明索引库UpdateRequest request = new UpdateRequest("test1","1");//设置修改的文档id和请求超时时间request.id("1").timeout("1s");request.doc(JSON.toJSONString(user),XContentType.JSON);//执行修改  修改的时候,如果对象中某个字段没有给值,那么也会修改成默认值UpdateResponse update = client.update(request,RequestOptions.DEFAULT);System.out.println(update);System.out.println(update.status());//ok}//查看文档是否存在@Testvoid existsDocument() throws IOException {GetRequest request = new GetRequest("test1","1");boolean exists = client.exists(request, RequestOptions.DEFAULT);//存在返回true,不存在返回falseSystem.out.println(exists);}//删除文档@Testvoid deleteDocument() throws IOException {DeleteRequest request = new DeleteRequest("test1","1");DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);System.out.println(delete);System.out.println(delete.status());//ok}//根据id获取文档@Testvoid getDocument() throws IOException {GetRequest request = new GetRequest("test1","1");GetResponse resp = client.get(request, RequestOptions.DEFAULT);System.out.println(resp);//获取文档内容的字符串,没有数据为nullSystem.out.println(resp.getSourceAsString());}//批量操作,修改和删除操作只是改变request即可@Testvoid bulkadd() throws IOException {BulkRequest bulkRequest = new BulkRequest();bulkRequest.timeout("10s");List<User> list = new ArrayList<>();list.add(new User("chen1",20));list.add(new User("chen2",20));list.add(new User("chen3",20));list.add(new User("chen4",20));list.add(new User("chen5",20));list.add(new User("chen6",20));list.add(new User("chen7",20));list.add(new User("chen8",20));//注意:id要是重复,则会覆盖掉for (int i = 0; i < list.size(); i++) {bulkRequest.add(new IndexRequest("test1").id(""+(i+1)).source(JSON.toJSONString(list.get(i)),XContentType.JSON));}//执行BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);System.out.println(bulk);System.out.println(bulk.status());}//条件查询文档@Testvoid searchDocument() throws IOException {//声明请求SearchRequest request = new SearchRequest("test1");//创建查询构造器对象SearchSourceBuilder builder = new SearchSourceBuilder();//精准查询条件构造器,还可以封装很多的构造器,都可以使用QueryBuilders这个类构建//QueryBuilders里面封装了我们使用的所有查询筛选命令TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "chen1");//把查询条件构造器放入到查询构造器中builder.query(termQueryBuilder);//把条件构造器放入到请求中request.source(builder);//执行查询SearchResponse search = client.search(request, RequestOptions.DEFAULT);//这个查询就和我们使用命令返回的结果是一致的System.out.println(JSON.toJSONString(search.getHits().getHits()));for (SearchHit hit : search.getHits().getHits()) {//遍历获取到的hits,让每一个hit封装为map形式System.out.println(hit.getSourceAsMap());}}
}

springframework实现对象操作es

es实体对象

org.springframework.data.annotation.Id;
org.springframework.data.elasticsearch.annotations.Document;
org.springframework.data.elasticsearch.annotations.Field;
org.springframework.data.elasticsearch.annotations.FieldType;

@Document(indexName = "bookinfosearch", type = "bookinfo")
public class BookInfoSearch implements Serializable {private static final long serialVersionUID = 1L;// 必须指定一个id,@Idprivate String id;// 这里配置了分词器,字段类型,可以不配置,默认也可// 名称@Field(type = FieldType.Text, analyzer = "ik_max_word")private String name;// 简称@Field(type = FieldType.Text, analyzer = "ik_max_word")private String bookName;//书本版本号private BigDecimal currentVersion;//书本首字母@Field(type = FieldType.Keyword)private String initials;//操作类型add update delete@Field(type = FieldType.Keyword)private String type;//书本分类信息的聚合体private List<String> tagJson;//分类Id@Field(type = FieldType.Keyword)private List<String> tagIds; //集合  1,2,3//分类名称@Field(type = FieldType.Keyword)private List<String> tagNames;//属性集合@Field(type = FieldType.Text, analyzer = "ik_smart")private List<String> attributes;//创建时间private Date createTime;//更新时间private Date updateTime;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public BigDecimal getCurrentVersion() {return currentVersion;}public void setCurrentVersion(BigDecimal currentVersion) {this.currentVersion = currentVersion;}public String getInitials() {return initials;}public void setInitials(String initials) {this.initials = initials;}public String getType() {return type;}public void setType(String type) {this.type = type;}public List<String> getTagIds() {return tagIds;}public void setTagIds(List<String> tagIds) {this.tagIds = tagIds;}public List<String> getTagNames() {return tagNames;}public void setTagNames(List<String> tagNames) {this.tagNames = tagNames;}public List<String> getAttributes() {return attributes;}public void setAttributes(List<String> attributes) {this.attributes = attributes;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}
}

es接口

org.springframework.data.repository.CrudRepository

public interface KgInfoSearchMapper extends CrudRepository<KgInfoSearch, String> {
}

AbstractResultMapper

类抽象结果映射器
org.springframework.data.elasticsearch.core

java.lang.Object
org.springframework.data.elasticsearch.core.AbstractResultMapper
所有已实现的接口:
GetResultMapper,MultiGetResultMapper,ResultMapper,SearchResultMapper
构造函数和描述

AbstractResultMapper(EntityMapper entityMapper) 

全部方法

EntityMapper	getEntityMapper() 
<T> T	mapEntity(String source, Class<T> clazz) 

在这里插入图片描述
在这里插入图片描述

public abstract class AbstractResultMapper implements ResultsMapper {private EntityMapper entityMapper;public AbstractResultMapper(EntityMapper entityMapper) {Assert.notNull(entityMapper, "EntityMapper must not be null!");this.entityMapper = entityMapper;}public <T> T mapEntity(String source, Class<T> clazz) {if (StringUtils.isEmpty(source)) {return null;} else {try {return this.entityMapper.mapToObject(source, clazz);} catch (IOException var4) {throw new ElasticsearchException("failed to map source [ " + source + "] to class " + clazz.getSimpleName(), var4);}}}public EntityMapper getEntityMapper() {return this.entityMapper;}
}

Mapper

org.springframework.data.elasticsearch

@Component
public class MyResultMapper extends AbstractResultMapper {private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;public MyResultMapper() {this(new SimpleElasticsearchMappingContext());}public MyResultMapper(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {super(new DefaultEntityMapper(mappingContext));Assert.notNull(mappingContext, "MappingContext must not be null!");this.mappingContext = mappingContext;}public MyResultMapper(EntityMapper entityMapper) {this(new SimpleElasticsearchMappingContext(), entityMapper);}public MyResultMapper(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext,EntityMapper entityMapper) {super(entityMapper);Assert.notNull(mappingContext, "MappingContext must not be null!");this.mappingContext = mappingContext;}@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {long totalHits = response.getHits().getTotalHits();float maxScore = response.getHits().getMaxScore();List<T> results = new ArrayList<>();for (SearchHit hit : response.getHits()) {if (hit != null) {T result = null;if (!StringUtils.isEmpty(hit.getSourceAsString())) {result = mapEntity(hit.getSourceAsString(), clazz);} else {result = mapEntity(hit.getFields().values(), clazz);}setPersistentEntityId(result, hit.getId(), clazz);setPersistentEntityVersion(result, hit.getVersion(), clazz);setPersistentEntityScore(result, hit.getScore(), clazz);populateScriptFields(result, hit);results.add(result);}}return new AggregatedPageImpl<T>(results, pageable, totalHits, response.getAggregations(), response.getScrollId(),maxScore);}private String concat(Text[] texts) {StringBuilder sb = new StringBuilder();for (Text text : texts) {sb.append(text.toString());}return sb.toString();}private <T> void populateScriptFields(T result, SearchHit hit) {if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);if (scriptedField != null) {String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();DocumentField searchHitField = hit.getFields().get(name);if (searchHitField != null) {field.setAccessible(true);try {field.set(result, searchHitField.getValue());} catch (IllegalArgumentException e) {throw new ElasticsearchException("failed to set scripted field: " + name + " with value: " + searchHitField.getValue(), e);} catch (IllegalAccessException e) {throw new ElasticsearchException("failed to access scripted field: " + name, e);}}}}}for (HighlightField field : hit.getHighlightFields().values()) {try {PropertyUtils.setProperty(result, field.getName(), concat(field.fragments()));} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {throw new ElasticsearchException("failed to set highlighted value for field: " + field.getName()+ " with value: " + Arrays.toString(field.getFragments()), e);}}}private <T> T mapEntity(Collection<DocumentField> values, Class<T> clazz) {return mapEntity(buildJSONFromFields(values), clazz);}private String buildJSONFromFields(Collection<DocumentField> values) {JsonFactory nodeFactory = new JsonFactory();try {ByteArrayOutputStream stream = new ByteArrayOutputStream();JsonGenerator generator = nodeFactory.createGenerator(stream, JsonEncoding.UTF8);generator.writeStartObject();for (DocumentField value : values) {if (value.getValues().size() > 1) {generator.writeArrayFieldStart(value.getName());for (Object val : value.getValues()) {generator.writeObject(val);}generator.writeEndArray();} else {generator.writeObjectField(value.getName(), value.getValue());}}generator.writeEndObject();generator.flush();return new String(stream.toByteArray(), Charset.forName("UTF-8"));} catch (IOException e) {return null;}}@Overridepublic <T> T mapResult(GetResponse response, Class<T> clazz) {T result = mapEntity(response.getSourceAsString(), clazz);if (result != null) {setPersistentEntityId(result, response.getId(), clazz);setPersistentEntityVersion(result, response.getVersion(), clazz);}return result;}@Overridepublic <T> LinkedList<T> mapResults(MultiGetResponse responses, Class<T> clazz) {LinkedList<T> list = new LinkedList<>();for (MultiGetItemResponse response : responses.getResponses()) {if (!response.isFailed() && response.getResponse().isExists()) {T result = mapEntity(response.getResponse().getSourceAsString(), clazz);setPersistentEntityId(result, response.getResponse().getId(), clazz);setPersistentEntityVersion(result, response.getResponse().getVersion(), clazz);list.add(result);}}return list;}private <T> void setPersistentEntityId(T result, String id, Class<T> clazz) {if (clazz.isAnnotationPresent(Document.class)) {ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(clazz);ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();// Only deal with String because ES generated Ids are strings !if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {persistentEntity.getPropertyAccessor(result).setProperty(idProperty, id);}}}private <T> void setPersistentEntityVersion(T result, long version, Class<T> clazz) {if (clazz.isAnnotationPresent(Document.class)) {ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(clazz);ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();// Only deal with Long because ES versions are longs !if (versionProperty != null && versionProperty.getType().isAssignableFrom(Long.class)) {// check that a version was actually returned in the response, -1 would indicate that// a search didn't request the version ids in the response, which would be an issueAssert.isTrue(version != -1, "Version in response is -1");persistentEntity.getPropertyAccessor(result).setProperty(versionProperty, version);}}}private <T> void setPersistentEntityScore(T result, float score, Class<T> clazz) {if (clazz.isAnnotationPresent(Document.class)) {ElasticsearchPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(clazz);if (!entity.hasScoreProperty()) {return;}entity.getPropertyAccessor(result) //.setProperty(entity.getScoreProperty(), score);}}
}

Service

    /*** 查询* @param bookInfoSearchQueryParam 和实体对象字段一样* @return*/PageEsResult searchInfoByBookName(BookInfoSearchQueryParam bookInfoSearchQueryParam);

ServiceImpl

@Overridepublic PageEsResult searchInfoByBookName(BookInfoSearchQueryParam bookInfoSearchQueryParam) {BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();//1. 创建一个查询条件对象if (bookInfoSearchQueryParam != null && ObjectUtil.isNotEmpty(bookInfoSearchQueryParam.getKey())) {String key = bookInfoSearchQueryParam.getKey();key = QueryParser.escape(key);MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders// 匹配多个字段 关键字 名称.multiMatchQuery(key, "name").analyzer("ik_max_word").field("name", 0.1f);queryBuilder.must(matchQueryBuilder);}if (bookInfoSearchQueryParam != null && ObjectUtil.isNotEmpty(bookInfoSearchQueryParam.getTagId())) {queryBuilder.must(QueryBuilders.termQuery("tagIds", bookInfoSearchQueryParam.getTagId()));}//2.创建聚合查询TermsAggregationBuilder agg = null;if (bookInfoSearchQueryParam != null && ObjectUtil.isNotEmpty(bookInfoSearchQueryParam.getAgg())) {agg = AggregationBuilders.terms(bookInfoSearchQueryParam.getAgg()).field(bookInfoSearchQueryParam.getAgg() + ".keyword").size(Integer.MAX_VALUE);;//keyword表示不使用分词进行聚合}String sortField = "";if (bookInfoSearchQueryParam != null && ObjectUtil.isNotEmpty(bookInfoSearchQueryParam.getSortField())) {sortField = bookInfoSearchQueryParam.getSortField();}String sortRule = "";if (bookInfoSearchQueryParam != null && ObjectUtil.isNotEmpty(bookInfoSearchQueryParam.getSortRule())) {sortRule = bookInfoSearchQueryParam.getSortRule();}NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();nativeSearchQueryBuilder.withTypes("bookinfo"); // 类型nativeSearchQueryBuilder.withIndices("bookinfosearch");//索引nativeSearchQueryBuilder.withQuery(queryBuilder); //添加查询条件if (agg != null) {nativeSearchQueryBuilder.addAggregation(agg);}if (bookInfoSearchQueryParam != null && ObjectUtil.isNotEmpty(bookInfoSearchQueryParam.getKey())) {HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'>").postTags("</font>");HighlightBuilder.Field fieldAttributes = new HighlightBuilder.Field("attributes").preTags("<font style='color:red'>").postTags("</font>");field.fragmentSize(500);nativeSearchQueryBuilder.withHighlightFields(field, fieldAttributes);}nativeSearchQueryBuilder.withPageable(PageRequest.of(bookInfoSearchQueryParam.getPage(), bookInfoSearchQueryParam.getPageSize())); //符合查询条件的文档分页(不是聚合的分页)if (ObjectUtil.isNotEmpty(sortField) && ObjectUtil.isNotEmpty(sortRule)) {nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(SortOrder.valueOf(sortRule)));}NativeSearchQuery build = nativeSearchQueryBuilder.build();// 执行查询AggregatedPage<KgInfoSearch> testEntities = elasticsearchTemplate.queryForPage(build, BookInfoSearch.class, myResultMapper);// 取出聚合结果ggregations entitiesAggregations = testEntities.getAggregations();Terms terms = (Terms) entitiesAggregations.asMap().get(bookInfoSearchQueryParam.getAgg());// 遍历取出聚合字段列的值,与对应的数量if (terms != null && terms.getBuckets() != null && terms.getBuckets().size() > 0) {for (Terms.Bucket bucket : terms.getBuckets()) {String keyAsString = bucket.getKeyAsString(); // 聚合字段列的值long docCount = bucket.getDocCount();// 聚合字段对应的数量log.info("keyAsString={},value={}", keyAsString, docCount);list集合.add(keyAsString);}}//搜索数据保存搜索历史JSONObject jsonObject = new JSONObject();jsonObject.put("key", bookInfoSearchQueryParam.getKey());jsonObject.put("key", bookInfoSearchQueryParam.getKey());return 接收result;}

请求参数Param对象
在es实体对象基础上 添加搜索条件字段

    private String sortField; //排序字段  时间:updateTime  /字母:initialsprivate String sortRule; //sortRule 排序规则 - 顺序(ASC)/倒序(DESC)private boolean allQuery =false;//是否全部查询private String agg;//聚类查询字段名称private String sessionId;private int pageSize = 10;private int page = 0;

http://www.ppmy.cn/news/179903.html

相关文章

vue2和vue3 子组件父组件之间的传值方法

vue父组件子组件传值 vue2和vue3子组件父组件之间的传值方法 在组件化开发的过程中难免会遇见 子组件和父组件之间的通讯那么这里讲关于vue2和vue3不同的通讯方式 先看一下vue2 父组件向子组件传递参数 父组件通过 :语法 其实就是v-bind 来传递参数 子组件通过 props来获取父组…

Yamaha DGX660 电钢琴aux-in只响一边的处理记录

想用电钢琴的喇叭来听手机上播放的音乐&#xff0c; 翻出来一根10年前的aux线&#xff0c;连上去试发现&#xff0c;电钢琴死活只有一边喇叭响 试来试去发现是线有问题&#xff0c;前面翻到的那根aux线&#xff0c; 是三段3.5mm的 插手机插电脑上都只有一个声道有电流。 下…

爵士鼓视频软件测试,【图片】电鼓和真鼓实际使用中的区别,买鼓的朋友可以参考【架子鼓吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 电鼓和真鼓实际使用中的区别。看到吧里很多人问买电鼓好还是真鼓好。首先不容置疑地说是真鼓好。下面我说说电鼓和真鼓的几点区别(此处应该有掌声)。我办公室放的是罗兰电鼓25lv&#xff0c;我回家到老师那里用的是t a m a真鼓。我…

MG调音台入门指南

MG调音台入门指南 https://list.youku.com/albumlist/show/id_50230099.html 调音台系统接好后&#xff0c;暂时先不要打开功率放大器或有源音箱的电源&#xff0c;打开调音台的电源后&#xff0c;不用按下任何按钮&#xff0c;也不用推上任何推子。 第一步确认输入信号是否正…

卡西欧CDP-100对战雅马哈镎-30 - 数码钢琴的比较

卡西欧CDP-100对战雅马哈镎-30 - 数码钢琴的比较 有很多人谁愿意弹钢琴中有自己的家。然而&#xff0c;传统的声学钢琴提供了许多弊端。它们又大又重&#xff0c;价格昂贵&#xff0c;他们跑调了。相反声学钢琴&#xff0c;一个明显的替代办法是得到一个数码钢琴。他们提供没有…

雅马哈推出“Thinking About Hearing Health”专题页面

日本滨松--(美国商业资讯)--雅马哈公司&#xff08;以下简称“雅马哈”&#xff09;将于世界卫生组织指定的3月3日国际爱耳日推出一个名为“Thinking About Hearing Health&#xff08;关注听力健康&#xff09;”的专题网页。最近有消息称&#xff0c;由于不健康的收听习惯&am…

雅马哈php mt7,雅马哈专业录音室监听耳机 HPH-MT7 正式发售!

从 NS-10M 监听音箱到 MSP 系列和 HS 系列&#xff0c;雅马哈始终秉持忠实的设计理念&#xff0c;聚焦声学精度&#xff0c;为音频专家提供出色的平台&#xff0c;构建并成就他们专属的专业之声。MT7录音室监听耳机承袭了这一基本研发理念,重现最为精细的声音&#xff0c;力求满…

Linux音频子系统(3) -代码分析(以YMU836为例)

0. 前言 数据流通过I2S的接口来传输&#xff0c;而I2c/Spi接口主要完成控制接口&#xff0c;例如控制声音的大小&#xff0c;功放的增益等操作。 platform 部分对应的代码在 kernel_3.10/sound/soc/fsl/fsl_ssi.c&#xff1b; codec 部分对应的代码在 kernel_3.10/sound/soc/co…