范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

ElasticSearch里我明明指定了long,为什么却变成了keyword

  背景
  实体类定义属性id为Long类型,但在调用 spring-data-elasticsearch:3.2.10.RELEASE中的putMapping(Class)方法时却被转换成了keyword类型源码
  查看putMapping方法,可以发现最终调用最下边的重载方法class ElasticsearchRestTemplate {   ...   @Override   public  boolean putMapping(Class clazz) {     return putMapping(clazz, buildMapping(clazz));   }    @Override   public  boolean putMapping(Class clazz, Object mapping) {     return putMapping(getPersistentEntityFor(clazz).getIndexName(), getPersistentEntityFor(clazz).getIndexType(),                       mapping);   }     @Override   public  boolean putMapping(String indexName, String type, Class clazz) {     return putMapping(indexName, type, buildMapping(clazz));   }     @Override   public boolean putMapping(String indexName, String type, Object mapping) {     Assert.notNull(indexName, "No index defined for putMapping()");     Assert.notNull(type, "No type defined for putMapping()");     PutMappingRequest request = new PutMappingRequest(indexName).type(type);     if (mapping instanceof String) {       request.source(String.valueOf(mapping), XContentType.JSON);     } else if (mapping instanceof Map) {       request.source((Map) mapping);     } else if (mapping instanceof XContentBuilder) {       request.source((XContentBuilder) mapping);     }     try {       return client.indices().putMapping(request, RequestOptions.DEFAULT).isAcknowledged();     } catch (IOException e) {       throw new ElasticsearchException("Failed to put mapping for " + indexName, e);     }   }   ... } 复制代码
  查看buildMapping方法,因为并没有定义外部mappingPath配置文件,所以走最下边的mappingBuilder.buildPropertyMapping(clazz)来进行解析出String类型的json文件abstract class AbstractElasticsearchTemplate {   ...   protected String buildMapping(Class<?> clazz) {     // load mapping specified in Mapping annotation if present     if (clazz.isAnnotationPresent(Mapping.class)) {       String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();       if (!StringUtils.isEmpty(mappingPath)) {         String mappings = ResourceUtil.readFileFromClasspath(mappingPath);         if (!StringUtils.isEmpty(mappings)) {           return mappings;         }       } else {         LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");       }     }       // build mapping from field annotations     try {       MappingBuilder mappingBuilder = new MappingBuilder(elasticsearchConverter);       return mappingBuilder.buildPropertyMapping(clazz);     } catch (Exception e) {       throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);     }   }   ... } 复制代码
  查看buildPropertyMapping方法class MappingBuilder {   ...   String buildPropertyMapping(Class<?> clazz) throws IOException {     // 提前解析出一些通用属性,比如indexName,indexType等等 		ElasticsearchPersistentEntity<?> entity = elasticsearchConverter.getMappingContext() 				.getRequiredPersistentEntity(clazz); 		// 构造一个json构造器,以indexType开始 		XContentBuilder builder = jsonBuilder().startObject().startObject(entity.getIndexType());  		// 添加dynamic template 		addDynamicTemplatesMapping(builder, entity);  		// 父子文档判断 		String parentType = entity.getParentType(); 		if (hasText(parentType)) { 			builder.startObject(FIELD_PARENT).field(FIELD_TYPE, parentType).endObject(); 		}  		// 属性解析开始标志properties 		builder.startObject(FIELD_PROPERTIES); 		// 具体的properties解析,为根对象非nested对象 		mapEntity(builder, entity, true, "", false, FieldType.Auto, null);  		builder.endObject() // FIELD_PROPERTIES 				.endObject() // indexType 				.endObject() // root object 				.close();  		return builder.getOutputStream().toString();   }      private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersistentEntity entity, boolean isRootObject, 			String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType, 			@Nullable Field parentFieldAnnotation) throws IOException {  		boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField); 		if (writeNestedProperties) {  			String type = nestedOrObjectField ? fieldType.toString().toLowerCase() 					: FieldType.Object.toString().toLowerCase(); 			builder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type);  			if (nestedOrObjectField && FieldType.Nested == fieldType && parentFieldAnnotation != null 					&& parentFieldAnnotation.includeInParent()) {  				builder.field("include_in_parent", parentFieldAnnotation.includeInParent()); 			}  			builder.startObject(FIELD_PROPERTIES); 		}     // 对象字段属性的解析 		if (entity != null) {  			entity.doWithProperties((PropertyHandler) property -> { 				try { 					if (property.isAnnotationPresent(Transient.class) || isInIgnoreFields(property, parentFieldAnnotation)) { 						return; 					}  					buildPropertyMapping(builder, isRootObject, property); 				} catch (IOException e) { 					logger.warn("error mapping property with name {}", property.getName(), e); 				} 			}); 		}  		if (writeNestedProperties) { 			builder.endObject().endObject(); 		} 	}   // 解析每个property的方法   private void buildPropertyMapping(XContentBuilder builder, boolean isRootObject, 			ElasticsearchPersistentProperty property) throws IOException {  		if (property.isAnnotationPresent(Mapping.class)) {  			String mappingPath = property.getRequiredAnnotation(Mapping.class).mappingPath(); 			if (!StringUtils.isEmpty(mappingPath)) {  				ClassPathResource mappings = new ClassPathResource(mappingPath); 				if (mappings.exists()) { 					builder.rawField(property.getFieldName(), mappings.getInputStream(), XContentType.JSON); 					return; 				} 			} 		} 		// geo标识 		boolean isGeoPointProperty = isGeoPointProperty(property);     // completion标识 		boolean isCompletionProperty = isCompletionProperty(property);     // nested object标识 		boolean isNestedOrObjectProperty = isNestedOrObjectProperty(property); 		// 属性上的Field注解 		Field fieldAnnotation = property.findAnnotation(Field.class); 		if (!isGeoPointProperty && !isCompletionProperty && property.isEntity() && hasRelevantAnnotation(property)) {  			if (fieldAnnotation == null) { 				return; 			}  			Iterator<? extends TypeInformation<?>> iterator = property.getPersistentEntityTypes().iterator(); 			ElasticsearchPersistentEntity<?> persistentEntity = iterator.hasNext() 					? elasticsearchConverter.getMappingContext().getPersistentEntity(iterator.next()) 					: null;  			mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty, 					fieldAnnotation.type(), fieldAnnotation);  			if (isNestedOrObjectProperty) { 				return; 			} 		}  		MultiField multiField = property.findAnnotation(MultiField.class);  		if (isGeoPointProperty) { 			applyGeoPointFieldMapping(builder, property); 			return; 		}  		if (isCompletionProperty) { 			CompletionField completionField = property.findAnnotation(CompletionField.class); 			applyCompletionFieldMapping(builder, property, completionField); 		} 		// 判断是否为id属性 		if (isRootObject && fieldAnnotation != null && property.isIdProperty()) { 			applyDefaultIdFieldMapping(builder, property); 		} else if (multiField != null) { 			addMultiFieldMapping(builder, property, multiField, isNestedOrObjectProperty); 		} else if (fieldAnnotation != null) { 			addSingleFieldMapping(builder, property, fieldAnnotation, isNestedOrObjectProperty); 		} 	}   ... } 复制代码
  至此可以看到,只要fieldName为id或document就判定为是id属性,然后将type设置为keyword并且可被索引。疑问到这里解决class SimpleElasticsearchPersistentProperty {   ...   private static final List SUPPORTED_ID_PROPERTY_NAMES = Arrays.asList("id", "document");   public SimpleElasticsearchPersistentProperty(Property property,       PersistentEntity<?, ElasticsearchPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {     ...     this.isId = super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName());     ...   }      @Override   public boolean isIdProperty() {     return isId;   }   private void applyDefaultIdFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)       throws IOException {       builder.startObject(property.getFieldName()).field(FIELD_TYPE, TYPE_VALUE_KEYWORD).field(FIELD_INDEX, true)         .endObject();   }   ... } 复制代码话外题
  项目中使用的ElasticSearch实体类都是采取@Document指定indexName来操作的,但是索引和表都涉及到分库分表,所以又不能写死,然后就采取的SpEL配合ThreadLocal从上下文里set后get,其实Spring对elasticsearch操作类似于关系型数据库也封装的有一层Repository抽象,名为ElasticsearchRepository,我们可以直接定义实体类操作接口继承就可以完成对单索引的CRUD以及Page等操作,但这样有一个问题,那就是indexName无法动态去调整,所以就放弃了这种,改用更底层的RestHighLevelClient封装的ElasticSearchRestTemplate模版类,这样在面对分库分表时就可以手动去对每个Document进行set不同的indexName,跨索引查询时也可以指定多个,也可以直接指定索引的alias,需要注意的时,在进行更新时,只指定alias是不被允许的,需要手动查出符合条件的Document在进行索引的分组批量更新,即调用ElasticSearch的bulk api
  在对ElasticSearch和数据库的一致性问题上,我是通过封装不同的方法来确保强一致性和最终一致性强一致性
  类似插入、更新、删除等场景下,都是放在一个事务里,先操作数据库,再操作ElasticSearch,这样可以确保操作ElasticSearch失败时,数据库可以成功回滚。一般只运用于对数据实时性要求敏感的场景,并且数据量不大的情况,但即便这样还是会有至少1s的延迟,这里就涉及到ElasticSearch的刷盘策略问题上了,这里不展开研究最终一致性
  批量的插入、更新这些操作,如果放在一个大事务里,对数据库也是一种压力,所以一般是分批操作数据库,另起一个线程池对事务提交进行监听,将数据库数据同步到ElasticSearch里,在同步成功后反转数据库的同步状态字段。为了确保万无一失,后台会启动一个定时扫描数据库同步字段的线程去定时扫描同步。这种一般适用于大数据量的场景。当然你也可以去监听MySQL的binlog日志来进行同步。

缺乏创新的笔电,走上了另一个极端?科技的进步正推动着许多产品朝极简化方向发展,逐渐去掉一些没必要的功能或设计。正如智能手机的发展历程一样,功能机时代的实体键盘滑盖翻盖等设计被简约的全面屏取代,笔记本电脑也是类似的情本地生活小程序小程序源码定制近几年城市化进程不断加快,很多年轻人都前往大城市谋求更多的发展机会,但对于初来乍到的年轻人而言,要解决衣食住行问题多少有些麻烦,为了给用户提供方便,本地生活小程序开发应运而生,为城java程序员一直在做增删改查很迷茫,该如何提升自己?编程语言说到底就是一种工具,至于能让编程语言发挥出什么样的价值,要结合编程的场景,以及具体的任务要求。研发人员往往会采用编程语言来完成系统级任务,而应用级程序员往往会使用编程语言来四大报头条数字经济利好,计算机受益。氢能概念不断升温一万亿宁王进军换电市场宁德时代将在18号举行换电品牌发布会。点评换电的发展,不论是对消费者换电站运营商还是电池厂均受益。并且换电模式的发展还有政策的扶持,有可能成为新的风口。换电概没有了华为这条鲶鱼,芯片和手机恐怕会陷入停滞状态新手机陷入了创新不足的困境了。现在的情况似乎属于是芯片厂家和手机厂家一起摆烂了,估计还是得来条鲶鱼。因为没有了华为这条鲶鱼,芯片和手机恐怕会陷入停滞状态,典型表现是没有麒麟,高通都OPPOFindX5背面颜值曝光?iPhoneA16芯片设计完成,4纳米工艺?OPPOFindX5系列有三款机型,它的背面颜值曝光,机身正面变化不大。从颜值上看,基本背面设计延续了FindX3系列的设计,但又有些不同,中杯采用的是一体化成型热弯工艺,陶瓷白质苹果接受涨价,包下台积电4纳米产能,将用于iPhone14由于疫情导致供应链危机,全球缺芯潮从去年持续至今,下游电子产品公司为了获得上游芯片代工厂的货源,即使涨价也只能接受。据台湾工商时报报道,台积电今年全面调涨芯片代工价格,作为其第一大比特币暴跌的原因都有哪些?作为一个大类资产,价格展示出更大的下探幅度相对于传统资产来说,其背后的原因一如所有金融产品波动之原因而多种多样,但其价格相对而言略脆弱毕竟还在早期。目前看美丽国加息是近期最大的影响苹果啥时候进货?又一款魔改C口iPhone来了完美保留防水1月17日,继全球第一台TypeC接口的iPhoneX被高价卖出后,又有大神受该项目的启发,打造了全球第二款魔改C口的iPhoneX。第二款就像升级迭代一样,在做工方面更加严实。第三星回归之后,荣耀小米们的高端化何去何从?图片来源视觉中国文丨互联网江湖正当国产手机品牌为冲击高端市场而战之时,三星要回归了。最近,有媒体报道三星方面成立了新的中国团队,计划重新回归国内手机市场。目前,自三星关闭了惠州工厂华为mate50系有望实现5G,采用14mm制程工艺的麒麟9000芯,期待吗华为mate系列和P系列能不能发布,能不能如期发布?华为的新机什么时候支持5G?华为鸿蒙系统3。0什么时候登场,这个是网友近期都比较关注的问题!一方面是对于华为的关心,希望华为能够
丰田亚洲龙试驾2。5L豪华版,实测百公里油耗8L!丰田亚洲龙作为一款中型车,虽然进入国内时间比较晚,但凭借高颜值获得了不错的销量成绩,在今年7月份一共卖出了9943台。亚洲龙实际价格上已经接近一部分入门级豪华车,厂商指导售价在19领克06试驾1。5T劲Pro,三缸发动机最大马力177匹!在小型SUV市场,领克06算是辨识度比较高的一款自主品牌车型,唯一算得上短板的地方就是价格不便宜,厂商指导售价在11。8613。86万之间。从销量上来看实际并不差,7月份卖出了41星越S试驾2。0TD自动两驱闪电版,配一体双联屏BOSE音响在国产品牌中,吉利汽车这几年表现不错,自从收购了沃尔沃之后,旗下一些车型被人们称之为小沃尔沃。今天要跟大家聊的是一款主打年轻人的星越S,从定位上来讲是一款紧凑型SUV,厂商指导售价7月卖出1。6万台,实拍奥迪A6L,车长超5米配19英寸轮毂!在中大型豪华车领域,奥迪A6L有点一骑绝尘的意思,在同价位车型中算是均衡的一款,消费者认可度不错,从7月份的数据来看,卖出了1。6万台,要比宝马5系多出了4000台。从价格上来看,超大尾翼亮黄装饰,百公里加速5。7秒,领克03Cyan亮相成都车展高性能车对年轻人来讲算是一个福音,目前国产品牌是往这一方向发展。在成都车展中,领克亮相了一款个性化定制性能车,名字叫做领克03Cyan定制款。外观上采用蓝色涂装,看上去特别帅气,在2022款长安CS75PLUS上市,起售11。79万,能否冲击哈弗H6地位?在国产SUV中,长安CS75PLUS对于销量王宝座一直虎视眈眈,作为一款后起之秀,这些年来备受认可。而目前2022款车型终于上市,新车型厂商指导售价在11。7915。49万之间,一林肯飞行家试驾3。0TV6四驱尊雅版,6座定位提供车顶行李架!高端车型,往往需要配备高端动力,个人认为3。0TV6发动机是基础。但实际上现在很多豪华车型入门级还是会选择2。0T涡轮引擎,甚至有一部分选择1。5T涡轮增压引擎。而今天跟大家来聊的改装宝骏Valli顶配,粉色回头率高,配10。25英寸大屏车联网对于小家庭用户来讲,旅行车算是不错的选择之一。在今年6月份宝骏汽车推出了Valli,相对于合资旅行车,价格更亲民一些,厂商指导售价在7。9810。58万之间。上市没有多久就入手了顶牧马人实拍2。0TSahara四门版,最大扭矩400Nm,底盘调校偏硬对于男生来讲,买车不一定要太过于细腻,反而是一些粗犷车型更容易吸引眼球。就比如说牧马人,说到牧马人很多人第一时间想到的就是越野,但实际现在很多人愿意在城市路段开越野车,第一是喜欢外华为加持,起售21。68万,增程式方案的赛力斯SF5实力如何?新能源车型有很多种解决方案,一种就是我们说的纯电动方案,还有一种就是增程式方案。今天要跟大家聊的这款车叫做赛力斯SF5,品牌知名度并不高,主要能够出圈是因为跟华为合作,目前在售一共本田URV实拍370TURBO四驱尊享版,5座定位配2。0T引擎日系SUV车型在国内一直很受关注,当然其中也有一些相对冷门的车型,比如说本田URV。目前在售版本车型在2020年6月份上市,外形上相对比较凶悍,作为一款中型SUV,并没有提供7座版