FileDocCategorySizeDatePackage
IndexSchema.javaAPI DocApache Lucene 2.1.015639Wed Feb 14 10:46:06 GMT 2007org.apache.lucene.gdata.search.config

IndexSchema.java

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.lucene.gdata.search.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.search.index.IndexDocument;
import org.apache.lucene.gdata.utils.ReflectionUtils;

/**
 * This class is used to configure the indexing and search component. Each
 * service on the GData server will have an own search index. For this purpose
 * one single index schema will be configured in the gdata-config.xml file. This
 * file will be mapped on this class on startup.
 * <p>
 * This class breaks some encapsulation of general java classes to be
 * configurable via the xml configuration file. The will be very less type and
 * value checking of the properties inside this file. Mandatory values must be
 * set in the configuration file. The server won't start up if these values are
 * missing. See definition in the xml schema file. If this class is instantiated
 * manually the value for the name of the schema should be set before this is
 * passed to the IndexController.
 * </p>
 * <p>
 * One IndexSchema consists of multiple instances of
 * {@link org.apache.lucene.gdata.search.config.IndexSchemaField} each of this
 * instances describes a single field in the index and all schema informations
 * about the field.
 * <p>
 * 
 * 
 * @see org.apache.lucene.gdata.search.config.IndexSchemaField
 * 
 * 
 * @author Simon Willnauer
 */
public class IndexSchema {
    private final Set<String> searchableFieldNames = new HashSet<String>();

    private static final Log LOG = LogFactory.getLog(IndexSchema.class);

    /**
     * a static final value for properties are not set by the configuration file
     * this value will be set to all long and int properties by default
     */
    public static final int NOT_SET_VALUE = -1;
    private static final int DEFAULT_OPTIMIZE_COUNT = 1;
    private static final int DEFAULT_COMMIT_COUNT = 1;

    private String indexLocation;

    /*
     * this should be final change it if possible --> see commons digester /
     * RegistryBuilder
     */
    private String name;

    private boolean useTimedIndexer;

    private long indexerIdleTime = NOT_SET_VALUE;

    private Analyzer serviceAnalyzer;

    private String defaultSearchField;

    private PerFieldAnalyzerWrapper perFieldAnalyzer;

    private Collection<IndexSchemaField> schemaFields;

    private int maxBufferedDocs = NOT_SET_VALUE;

    private int maxMergeDocs = NOT_SET_VALUE;

    private int mergeFactor = NOT_SET_VALUE;

    private int maxFieldLength = NOT_SET_VALUE;

    private long writeLockTimeout = NOT_SET_VALUE;

    private long commitLockTimeout = NOT_SET_VALUE;

    private int commitAfterDocuments = DEFAULT_COMMIT_COUNT;
    
    private int optimizeAfterCommit = DEFAULT_OPTIMIZE_COUNT;
    
    private boolean useCompoundFile = false;

    /**
     * Creates a new IndexSchema and initialize the standard service analyzer to
     * {@link StandardAnalyzer}
     * 
     */
    public IndexSchema() {
        this.schemaFields = new ArrayList<IndexSchemaField>();
        /*
         * keep as standard if omitted in the configuration
         */
        this.serviceAnalyzer = new StandardAnalyzer();

    }

    /**
     * Initialize the schema and checks all required values
     */
    public void initialize() {
        for (IndexSchemaField field : this.schemaFields) {
            if (!field.checkRequieredValues())
                throw new RuntimeException("Required Value for field: "
                        + field.getName() + " is missing");
        }
        if (this.defaultSearchField == null)
            throw new RuntimeException("DefaulSearchField must not be null");
        if (this.name == null)
            throw new RuntimeException(
                    "Schema field is not set -- must not be null");
        if (this.indexLocation == null)
            throw new RuntimeException("IndexLocation must not be null");
        if(!this.searchableFieldNames.contains(this.defaultSearchField)){
            throw new RuntimeException("the default search field: "+this.defaultSearchField+" is registered as a field");
        }

    }

    /**
     * @return Returns the useCompoundFile.
     */
    public boolean isUseCompoundFile() {
        return this.useCompoundFile;
    }

    /**
     * @param useCompoundFile
     *            The useCompoundFile to set.
     */
    public void setUseCompoundFile(boolean useCompoundFile) {
        this.useCompoundFile = useCompoundFile;
    }

    /**
     * Adds a new {@link IndexSchemaField} to the schema. if the fields name
     * equals {@link IndexDocument#FIELD_ENTRY_ID} or the field is
     * <code>null</code> it will simply ignored
     * 
     * @param field -
     *            the index schema field to add as a field of this schema.
     */
    public void addSchemaField(final IndexSchemaField field) {
        if (field == null)
            return;
        /*
         * skip fields configured in the gdata-config.xml file if their names
         * match a primary key field id of the IndexDocument
         */
        if (field.getName().equals(IndexDocument.FIELD_ENTRY_ID)
                || field.getName().equals(IndexDocument.FIELD_FEED_ID))
            return;
        if (field.getAnalyzerClass() != null) {
            /*
             * enable per field analyzer if one is set.
             */
            Analyzer analyzer = getAnalyzerInstance(field.getAnalyzerClass());
            /*
             * null values will be omitted here
             */
            buildPerFieldAnalyzerWrapper(analyzer, field.getName());
        }
        this.schemaFields.add(field);
        this.searchableFieldNames.add(field.getName());
    }


    /**
     * @return Returns the fieldConfiguration.
     */
    public Collection<IndexSchemaField> getFields() {
        return this.schemaFields;
    }

    /**
     * @return - the analyzer instance to be used for this schema
     */
    public Analyzer getSchemaAnalyzer() {
        if (this.perFieldAnalyzer == null)
            return this.serviceAnalyzer;
        return this.perFieldAnalyzer;
    }

    /**
     * @return Returns the serviceAnalyzer.
     */
    public Analyzer getServiceAnalyzer() {
        return this.serviceAnalyzer;
    }

    /**
     * @param serviceAnalyzer
     *            The serviceAnalyzer to set.
     */
    public void setServiceAnalyzer(Analyzer serviceAnalyzer) {
        if (serviceAnalyzer == null)
            return;
        this.serviceAnalyzer = serviceAnalyzer;

    }

    /**
     * @return Returns the commitLockTimout.
     */
    public long getCommitLockTimeout() {
        return this.commitLockTimeout;
    }

    /**
     * 
     * @param commitLockTimeout
     *            The commitLockTimeout to set.
     */
    public void setCommitLockTimeout(long commitLockTimeout) {
        // TODO enable this in config
        this.commitLockTimeout = commitLockTimeout;
    }

    /**
     * @return Returns the maxBufferedDocs.
     */
    public int getMaxBufferedDocs() {

        return this.maxBufferedDocs;
    }

    /**
     * @param maxBufferedDocs
     *            The maxBufferedDocs to set.
     */
    public void setMaxBufferedDocs(int maxBufferedDocs) {
        this.maxBufferedDocs = maxBufferedDocs;
    }

    /**
     * @return Returns the maxFieldLength.
     */
    public int getMaxFieldLength() {
        return this.maxFieldLength;
    }

    /**
     * @param maxFieldLength
     *            The maxFieldLength to set.
     */
    public void setMaxFieldLength(int maxFieldLength) {
        this.maxFieldLength = maxFieldLength;
    }

    /**
     * @return Returns the maxMergeDocs.
     */
    public int getMaxMergeDocs() {
        return this.maxMergeDocs;
    }

    /**
     * @param maxMergeDocs
     *            The maxMergeDocs to set.
     */
    public void setMaxMergeDocs(int maxMergeDocs) {
        this.maxMergeDocs = maxMergeDocs;
    }

    /**
     * @return Returns the mergeFactor.
     */
    public int getMergeFactor() {
        return this.mergeFactor;
    }

    /**
     * @param mergeFactor
     *            The mergeFactor to set.
     */
    public void setMergeFactor(int mergeFactor) {
        this.mergeFactor = mergeFactor;
    }

    /**
     * @return Returns the writeLockTimeout.
     */
    public long getWriteLockTimeout() {
        return this.writeLockTimeout;
    }

    /**
     * @param writeLockTimeout
     *            The writeLockTimeout to set.
     */
    public void setWriteLockTimeout(long writeLockTimeout) {
        this.writeLockTimeout = writeLockTimeout;
    }

    /**
     * @param fields
     *            The fieldConfiguration to set.
     */
    public void setSchemaFields(Collection<IndexSchemaField> fields) {
        this.schemaFields = fields;
    }

    /**
     * @return Returns the name.
     */
    public String getName() {
        return this.name;
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object object) {
        if (this == object)
            return true;
        if (object == null)
            return false;
        if (object instanceof IndexSchema) {
           if(this.name ==null)
               return super.equals(object);
            return this.name.equals(((IndexSchema) object).getName());
        }
        return false;
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        if (this.name == null)
            return super.hashCode();
        return this.name.hashCode();
    }

    private void buildPerFieldAnalyzerWrapper(Analyzer anazlyer, String field) {
        if (anazlyer == null || field == null || field.length() == 0)
            return;
        if (this.perFieldAnalyzer == null)
            this.perFieldAnalyzer = new PerFieldAnalyzerWrapper(
                    this.serviceAnalyzer);
        this.perFieldAnalyzer.addAnalyzer(field, anazlyer);
    }

    private static Analyzer getAnalyzerInstance(Class<? extends Analyzer> clazz) {
        if (!ReflectionUtils.extendsType(clazz, Analyzer.class)) {
            LOG.warn("Can not create analyzer for class " + clazz.getName());
            return null;
        }
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            LOG.warn("Can not create analyzer for class " + clazz.getName());
        }
        return null;
    }

    /**
     * @param name
     *            The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return Returns the indexLocation.
     */
    public String getIndexLocation() {
        return this.indexLocation;
    }

    /**
     * @param indexLocation
     *            The indexLocation to set.
     */
    public void setIndexLocation(String indexLocation) {
        this.indexLocation = indexLocation;
    }

    /**
     * @return Returns the defaultField.
     */
    public String getDefaultSearchField() {
        return this.defaultSearchField;
    }

    /**
     * @param defaultField
     *            The defaultField to set.
     */
    public void setDefaultSearchField(String defaultField) {
        this.defaultSearchField = defaultField;
    }

    /**
     * @return Returns the indexerIdleTime.
     */
    public long getIndexerIdleTime() {
        return this.indexerIdleTime;
    }

    /**
     * @param indexerIdleTime
     *            The indexerIdleTime to set.
     */
    public void setIndexerIdleTime(long indexerIdleTime) {
        this.indexerIdleTime = indexerIdleTime;
    }

    /**
     * @return Returns the useTimedIndexer.
     */
    public boolean isUseTimedIndexer() {
        return this.useTimedIndexer;
    }

    /**
     * @param useTimedIndexer
     *            The useTimedIndexer to set.
     */
    public void setUseTimedIndexer(boolean useTimedIndexer) {
        this.useTimedIndexer = useTimedIndexer;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder(this.getClass().getName())
                .append(" ");
        builder.append("Name: ").append(this.name).append(" ");
        builder.append("MaxBufferedDocs: ").append(this.maxBufferedDocs)
                .append(" ");
        builder.append("MaxFieldLength: ").append(this.maxFieldLength).append(
                " ");
        builder.append("MaxMergeDocs: ").append(this.maxMergeDocs).append(" ");
        builder.append("MergeFactor: ").append(this.mergeFactor).append(" ");
        builder.append("CommitLockTimeout: ").append(this.commitLockTimeout)
                .append(" ");
        builder.append("WriteLockTimeout: ").append(this.writeLockTimeout)
                .append(" ");
        builder.append("indexerIdleTime: ").append(this.indexerIdleTime)
                .append(" ");
        builder.append("useCompoundFile: ").append(this.useCompoundFile)
                .append(" ");
        builder.append("Added SchemaField instances: ").append(
                this.schemaFields.size()).append(" ");

        builder.append("IndexLocation: ").append(this.indexLocation)
                .append(" ");
        return builder.toString();

    }

    /**
     * @return Returns the searchableFieldNames.
     */
    public Set<String> getSearchableFieldNames() {
        return this.searchableFieldNames;
    }

    /**
     * Defines after how many added,removed or updated document the indexer should commit.
     * @return Returns the commitAfterDocuments.
     */
    public int getCommitAfterDocuments() {
        return this.commitAfterDocuments;
    }

    /**
     * @param commitAfterDocuments The commitAfterDocuments to set.
     */
    public void setCommitAfterDocuments(int commitAfterDocuments) {
        if(commitAfterDocuments < DEFAULT_COMMIT_COUNT)
            return;
        this.commitAfterDocuments = commitAfterDocuments;
    }

    /**
     * Defines after how many commits the indexer should optimize the index
     * @return Returns the optimizeAfterCommit.
     */
    public int getOptimizeAfterCommit() {
        
        return this.optimizeAfterCommit;
    }

    /**
     * @param optimizeAfterCommit The optimizeAfterCommit to set.
     */
    public void setOptimizeAfterCommit(int optimizeAfterCommit) {
        if(optimizeAfterCommit < DEFAULT_OPTIMIZE_COUNT )
            return;
        this.optimizeAfterCommit = optimizeAfterCommit;
    }
}