elasticsearch index 之 put mapping

來源:互聯網
上載者:User

標籤:idt   詳細   cut   last   沒有   pes   span   建立   arc   

mapping機制使得elasticsearch索引資料變的更加靈活,近乎於no schema。mapping可以在建立索引時設定,也可以在後期設定。後期設定可以是修改mapping(無法對已有的field屬性進行修改,一般來說只是增加新的field)或者對沒有mapping的索引設定mapping。put mapping操作必須是master節點來完成,因為它涉及到叢集matedata的修改,同時它跟index和type密切相關。修改只是針對特定index的特定type。

在Action support分析中我們分析過幾種Action的抽象類別型,put mapping Action屬於TransportMasterNodeOperationAction的子類。它實現了masterOperation方法,每個繼承自TransportMasterNodeOperationAction的子類都會根據自己的具體功能來實現這個方法。這裡的實現如下所示:

    protected void masterOperation(final PutMappingRequest request, final ClusterState state, final ActionListener<PutMappingResponse> listener) throws ElasticsearchException {        final String[] concreteIndices = clusterService.state().metaData().concreteIndices(request.indicesOptions(), request.indices());
      //構造request PutMappingClusterStateUpdateRequest updateRequest = new PutMappingClusterStateUpdateRequest() .ackTimeout(request.timeout()).masterNodeTimeout(request.masterNodeTimeout()) .indices(concreteIndices).type(request.type()) .source(request.source()).ignoreConflicts(request.ignoreConflicts());      //調用putMapping方法,同時傳入一個Listener metaDataMappingService.putMapping(updateRequest, new ActionListener<ClusterStateUpdateResponse>() { @Override public void onResponse(ClusterStateUpdateResponse response) { listener.onResponse(new PutMappingResponse(response.isAcknowledged())); } @Override public void onFailure(Throwable t) { logger.debug("failed to put mappings on indices [{}], type [{}]", t, concreteIndices, request.type()); listener.onFailure(t); } }); }

以上是TransportPutMappingAction對masterOperation方法的實現,這裡並沒有多少複雜的邏輯和操作。具體操作在matedataMappingService中。跟之前的CreateIndex一樣,put Mapping也是向master提交一個updateTask。所有邏輯也都在execute方法中。這個task的基本跟CreateIndex一樣,也需要在給定的時間內響應。它的代碼如下所示:

 public void putMapping(final PutMappingClusterStateUpdateRequest request, final ActionListener<ClusterStateUpdateResponse> listener) {    //提交一個高基本的updateTask        clusterService.submitStateUpdateTask("put-mapping [" + request.type() + "]", Priority.HIGH, new AckedClusterStateUpdateTask<ClusterStateUpdateResponse>(request, listener) {            @Override            protected ClusterStateUpdateResponse newResponse(boolean acknowledged) {                return new ClusterStateUpdateResponse(acknowledged);            }            @Override            public ClusterState execute(final ClusterState currentState) throws Exception {                List<String> indicesToClose = Lists.newArrayList();                try {
            //必須針對已經在matadata中存在的index,否則拋出異常 for (String index : request.indices()) { if (!currentState.metaData().hasIndex(index)) { throw new IndexMissingException(new Index(index)); } } //還需要存在於indices中,否則無法進行操作。所以這裡要進行預建 for (String index : request.indices()) { if (indicesService.hasIndex(index)) { continue; } final IndexMetaData indexMetaData = currentState.metaData().index(index);
              //不存在就進行建立 IndexService indexService = indicesService.createIndex(indexMetaData.index(), indexMetaData.settings(), clusterService.localNode().id()); indicesToClose.add(indexMetaData.index()); // make sure to add custom default mapping if exists if (indexMetaData.mappings().containsKey(MapperService.DEFAULT_MAPPING)) { indexService.mapperService().merge(MapperService.DEFAULT_MAPPING, indexMetaData.mappings().get(MapperService.DEFAULT_MAPPING).source(), false); } // only add the current relevant mapping (if exists) if (indexMetaData.mappings().containsKey(request.type())) { indexService.mapperService().merge(request.type(), indexMetaData.mappings().get(request.type()).source(), false); } }            //合并更新Mapping Map<String, DocumentMapper> newMappers = newHashMap(); Map<String, DocumentMapper> existingMappers = newHashMap();
            //針對每個index進行Mapping合并 for (String index : request.indices()) { IndexService indexService = indicesService.indexServiceSafe(index); // try and parse it (no need to add it here) so we can bail early in case of parsing exception DocumentMapper newMapper; DocumentMapper existingMapper = indexService.mapperService().documentMapper(request.type()); if (MapperService.DEFAULT_MAPPING.equals(request.type())) {//存在defaultmapping則合并default mapping // _default_ types do not go through merging, but we do test the new settings. Also don‘t apply the old default newMapper = indexService.mapperService().parse(request.type(), new CompressedString(request.source()), false); } else { newMapper = indexService.mapperService().parse(request.type(), new CompressedString(request.source()), existingMapper == null); if (existingMapper != null) { // first, simulate DocumentMapper.MergeResult mergeResult = existingMapper.merge(newMapper, mergeFlags().simulate(true)); // if we have conflicts, and we are not supposed to ignore them, throw an exception if (!request.ignoreConflicts() && mergeResult.hasConflicts()) { throw new MergeMappingException(mergeResult.conflicts()); } } } newMappers.put(index, newMapper); if (existingMapper != null) { existingMappers.put(index, existingMapper); } } String mappingType = request.type(); if (mappingType == null) { mappingType = newMappers.values().iterator().next().type(); } else if (!mappingType.equals(newMappers.values().iterator().next().type())) { throw new InvalidTypeNameException("Type name provided does not match type name within mapping definition"); } if (!MapperService.DEFAULT_MAPPING.equals(mappingType) && !PercolatorService.TYPE_NAME.equals(mappingType) && mappingType.charAt(0) == ‘_‘) { throw new InvalidTypeNameException("Document mapping type name can‘t start with ‘_‘"); } final Map<String, MappingMetaData> mappings = newHashMap(); for (Map.Entry<String, DocumentMapper> entry : newMappers.entrySet()) { String index = entry.getKey(); // do the actual merge here on the master, and update the mapping source DocumentMapper newMapper = entry.getValue(); IndexService indexService = indicesService.indexService(index); if (indexService == null) { continue; } CompressedString existingSource = null; if (existingMappers.containsKey(entry.getKey())) { existingSource = existingMappers.get(entry.getKey()).mappingSource(); } DocumentMapper mergedMapper = indexService.mapperService().merge(newMapper.type(), newMapper.mappingSource(), false); CompressedString updatedSource = mergedMapper.mappingSource(); if (existingSource != null) { if (existingSource.equals(updatedSource)) { // same source, no changes, ignore it } else { // use the merged mapping source mappings.put(index, new MappingMetaData(mergedMapper)); if (logger.isDebugEnabled()) { logger.debug("[{}] update_mapping [{}] with source [{}]", index, mergedMapper.type(), updatedSource); } else if (logger.isInfoEnabled()) { logger.info("[{}] update_mapping [{}]", index, mergedMapper.type()); } } } else { mappings.put(index, new MappingMetaData(mergedMapper)); if (logger.isDebugEnabled()) { logger.debug("[{}] create_mapping [{}] with source [{}]", index, newMapper.type(), updatedSource); } else if (logger.isInfoEnabled()) { logger.info("[{}] create_mapping [{}]", index, newMapper.type()); } } } if (mappings.isEmpty()) { // no changes, return return currentState; }            //根據mapping的更新情況重建matadata MetaData.Builder builder = MetaData.builder(currentState.metaData()); for (String indexName : request.indices()) { IndexMetaData indexMetaData = currentState.metaData().index(indexName); if (indexMetaData == null) { throw new IndexMissingException(new Index(indexName)); } MappingMetaData mappingMd = mappings.get(indexName); if (mappingMd != null) { builder.put(IndexMetaData.builder(indexMetaData).putMapping(mappingMd)); } } return ClusterState.builder(currentState).metaData(builder).build(); } finally { for (String index : indicesToClose) { indicesService.removeIndex(index, "created for mapping processing"); } } } }); }

 以上就是mapping的設定過程,首先它跟Create index一樣,只有master節點才能操作,而且是以task的形式提交給master;其次它的本質是將request中的mapping和index現存的或者是default mapping合并,並最終產生新的matadata更新到叢集的各個節點。

總結:叢集中的master操作無論是index方面還是叢集方面,最終都是叢集matadata的更新過程。而這些操作只能在master上進行,並且都是會逾時的任務。put mapping當然也不例外。上面的兩段代碼基本概況了mapping的設定過程。這裡就不再重複了。這裡還有一個問題沒有涉及到就是mapping的合并。mapping合并會在很多地方用到。在下一節中會它進行詳細分析。

elasticsearch index 之 put mapping

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.