Package org.grails.plugins.elasticsearch.mapping

Source Code of org.grails.plugins.elasticsearch.mapping.SearchableClassMappingConfigurator

/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.grails.plugins.elasticsearch.mapping;

import groovy.util.ConfigObject;
import org.apache.log4j.Logger;
import org.codehaus.groovy.grails.commons.*;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.indices.IndexAlreadyExistsException;
import org.elasticsearch.transport.RemoteTransportException;
import org.grails.plugins.elasticsearch.ElasticSearchContextHolder;

import java.util.*;

/**
* Build searchable mappings, configure ElasticSearch indexes,
* build and install ElasticSearch mappings.
*/
public class SearchableClassMappingConfigurator {

    private static final Logger LOG = Logger.getLogger(SearchableClassMappingConfigurator.class);

    private ElasticSearchContextHolder elasticSearchContext;
    private GrailsApplication grailsApplication;
    private Client elasticSearchClient;
    private ConfigObject config;

    /**
     * Init method.
     */
    public void configureAndInstallMappings() {
        Collection<SearchableClassMapping> mappings = buildMappings();
        installMappings(mappings);
    }

    /**
     * Resolve the ElasticSearch mapping from the static "searchable" property (closure or boolean) in domain classes
     * @param mappings searchable class mappings to be install.
     */
    public void installMappings(Collection<SearchableClassMapping> mappings) {
        Set<String> installedIndices = new HashSet<String>();
        Map<String, Object> settings = new HashMap<String, Object>();
//        settings.put("number_of_shards", 5);        // must have 5 shards to be Green.
//        settings.put("number_of_replicas", 2);
        settings.put("number_of_replicas", 0);
        // Look for default index settings.
        Map esConfig = (Map) ConfigurationHolder.getConfig().getProperty("elasticSearch");
        if (esConfig != null) {
            @SuppressWarnings({"unchecked"})
            Map<String, Object> indexDefaults = (Map<String, Object>) esConfig.get("index");
            LOG.debug("Retrieved index settings");
            if (indexDefaults != null) {
                for(Map.Entry<String, Object> entry : indexDefaults.entrySet()) {
                    settings.put("index." + entry.getKey(), entry.getValue());
                }
            }
        }
        LOG.debug("Installing mappings...");
        for(SearchableClassMapping scm : mappings) {
            if (scm.isRoot()) {
                Map elasticMapping = ElasticSearchMappingFactory.getElasticMapping(scm);

                // todo wait for success, maybe retry.
                // If the index does not exist, create it
                if (!installedIndices.contains(scm.getIndexName())) {
                    LOG.debug("Index " + scm.getIndexName() + " does not exists, initiating creation...");
                    try {
                        // Could be blocked on index level, thus wait.
                        try {
                            LOG.debug("Waiting at least yellow status on " + scm.getIndexName() + " ...");
                            elasticSearchClient.admin().cluster().prepareHealth(scm.getIndexName())
                                    .setWaitForYellowStatus()
                                    .execute().actionGet();
                        } catch (Exception e) {
                            // ignore any exceptions due to non-existing index.
                            LOG.debug("Index health", e);
                        }
                        elasticSearchClient.admin().indices().prepareCreate(scm.getIndexName())
                                .setSettings(settings)
                                .execute().actionGet();
                        installedIndices.add(scm.getIndexName());
                        LOG.debug(elasticMapping.toString());

                        // If the index already exists, ignore the exception
                    } catch (IndexAlreadyExistsException iaee) {
                        LOG.debug("Index " + scm.getIndexName() + " already exists, skip index creation.");
                    } catch (RemoteTransportException rte) {
                        LOG.debug(rte.getMessage());
                    }
                }

                // Install mapping
                // todo when conflict is detected, delete old mapping (this will delete all indexes as well, so should warn user)
                if (LOG.isDebugEnabled()) {
                    LOG.debug("[" + scm.getElasticTypeName() + "] => " + elasticMapping);
                }
                elasticSearchClient.admin().indices().putMapping(
                        new PutMappingRequest(scm.getIndexName())
                                .type(scm.getElasticTypeName())
                                .source(elasticMapping)
                ).actionGet();
            }

        }

        ClusterHealthResponse response = elasticSearchClient.admin().cluster().health(new ClusterHealthRequest().waitForYellowStatus()).actionGet();
        LOG.debug("Cluster status: " + response.getStatus());
    }

    private Collection<SearchableClassMapping> buildMappings() {
        List<SearchableClassMapping> mappings = new ArrayList<SearchableClassMapping>();
        for(GrailsClass clazz : grailsApplication.getArtefacts(DomainClassArtefactHandler.TYPE)) {
            GrailsDomainClass domainClass = (GrailsDomainClass) clazz;
            SearchableDomainClassMapper mapper = new SearchableDomainClassMapper(grailsApplication, domainClass, config);
            SearchableClassMapping searchableClassMapping = mapper.buildClassMapping();
            if (searchableClassMapping != null) {
                elasticSearchContext.addMappingContext(searchableClassMapping);
                mappings.add(searchableClassMapping);
            }
        }

        // Inject cross-referenced component mappings.
        for(SearchableClassMapping scm : mappings) {
            for(SearchableClassPropertyMapping scpm : scm.getPropertiesMapping()) {
                if (scpm.isComponent()) {
                    Class<?> componentType = scpm.getGrailsProperty().getReferencedPropertyType();
                    scpm.setComponentPropertyMapping(elasticSearchContext.getMappingContextByType(componentType));
                }
            }
        }

        // Validate all mappings to make sure any cross-references are fine.
        for(SearchableClassMapping scm : mappings) {
            scm.validate(elasticSearchContext);
        }

        return mappings;
    }

    public void setElasticSearchContext(ElasticSearchContextHolder elasticSearchContext) {
        this.elasticSearchContext = elasticSearchContext;
    }

    public void setGrailsApplication(GrailsApplication grailsApplication) {
        this.grailsApplication = grailsApplication;
    }

    public void setElasticSearchClient(Client elasticSearchClient) {
        this.elasticSearchClient = elasticSearchClient;
    }

    public void setConfig(ConfigObject config) {
        this.config = config;
    }
}
TOP

Related Classes of org.grails.plugins.elasticsearch.mapping.SearchableClassMappingConfigurator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.