org.apache.accumulo.core.client.summary.SummarizerConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.accumulo.core.client.summary.SummarizerConfiguration.java

Source

/*
 * 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.accumulo.core.client.summary;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.accumulo.core.summary.SummarizerConfigurationUtil;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;

/**
 * This class encapsulates the configuration needed to instantiate a {@link Summarizer}. It also
 * provides methods and documentation for setting the table properties that configure a Summarizer.
 *
 * @since 2.0.0
 */
public class SummarizerConfiguration {

    private final String className;
    private final Map<String, String> options;
    private int hashCode = 0;
    private final String configId;

    private SummarizerConfiguration(String className, String configId, Map<String, String> options) {
        this.className = className;
        this.options = ImmutableMap.copyOf(options);

        if (configId == null) {
            ArrayList<String> keys = new ArrayList<>(this.options.keySet());
            Collections.sort(keys);
            Hasher hasher = Hashing.murmur3_32().newHasher();
            hasher.putString(className, UTF_8);
            for (String key : keys) {
                hasher.putString(key, UTF_8);
                hasher.putString(options.get(key), UTF_8);
            }

            this.configId = hasher.hash().toString();
        } else {
            this.configId = configId;
        }
    }

    /**
     * @return the name of a class that implements @link {@link Summarizer}.
     */
    public String getClassName() {
        return className;
    }

    /**
     * @return custom options for a {link @Summarizer}
     */
    public Map<String, String> getOptions() {
        return options;
    }

    /**
     * The propertyId is used to when creating table properties for a summarizer. Its not used for
     * equality or hashCode for this class.
     */
    public String getPropertyId() {
        return configId;
    }

    @Override
    public String toString() {
        return className + " " + configId + " " + options;
    }

    /**
     * Compares the classname and options to determine equality.
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof SummarizerConfiguration) {
            SummarizerConfiguration osc = (SummarizerConfiguration) o;
            return className.equals(osc.className) && options.equals(osc.options);
        }

        return false;
    }

    /**
     * Hashes the classname and options to create a hashcode.
     */
    @Override
    public int hashCode() {
        if (hashCode == 0) {
            hashCode = 31 * options.hashCode() + className.hashCode();
        }
        return hashCode;
    }

    /**
     * Converts this configuration to Accumulo per table properties. The returned map has the
     * following key values. The {@code <configId>} below is from {@link #getPropertyId()}. The
     * {@code <optionKey>} and {@code <optionValue>} below are derived from the key values of
     * {@link #getOptions()}.
     *
     * <pre>
     * {@code
     *   table.summarizer.<configId>=<classname>
     *   table.summarizer.<configId>.opt.<optionKey1>=<optionValue1>
     *   table.summarizer.<configId>.opt.<optionKey2>=<optionValue2>
     *      .
     *      .
     *      .
     *   table.summarizer.<configId>.opt.<optionKeyN>=<optionValueN>
     * }
     * </pre>
     */
    public Map<String, String> toTableProperties() {
        return SummarizerConfigurationUtil.toTablePropertiesMap(Collections.singletonList(this));
    }

    /**
     * Encodes each configuration in the same way as {@link #toTableProperties()}.
     *
     * @throws IllegalArgumentException
     *           when there are duplicate values for {@link #getPropertyId()}
     */
    public static Map<String, String> toTableProperties(SummarizerConfiguration... configurations) {
        return SummarizerConfigurationUtil.toTablePropertiesMap(Arrays.asList(configurations));
    }

    /**
     * Encodes each configuration in the same way as {@link #toTableProperties()}.
     *
     * @throws IllegalArgumentException
     *           when there are duplicate values for {@link #getPropertyId()}
     */
    public static Map<String, String> toTableProperties(Collection<SummarizerConfiguration> configurations) {
        return SummarizerConfigurationUtil.toTablePropertiesMap(new ArrayList<>(configurations));
    }

    /**
     * Decodes table properties with the prefix {@code table.summarizer} into
     * {@link SummarizerConfiguration} objects. Table properties with prefixes other than
     * {@code table.summarizer} are ignored.
     */
    public static Collection<SummarizerConfiguration> fromTableProperties(Map<String, String> props) {
        return fromTableProperties(props.entrySet());
    }

    /**
     * @see #fromTableProperties(Map)
     */
    public static Collection<SummarizerConfiguration> fromTableProperties(Iterable<Entry<String, String>> props) {
        return SummarizerConfigurationUtil.getSummarizerConfigs(props);
    }

    /**
     * @since 2.0.0
     */
    public static class Builder {
        private String className;
        private ImmutableMap.Builder<String, String> imBuilder;
        private String configId = null;

        private Builder(String className) {
            this.className = className;
            this.imBuilder = ImmutableMap.builder();
        }

        /**
         * Sets the id used when generating table properties. Setting this is optional. If not set, an
         * id is generated using hashing that will likely be unique.
         *
         * @param propId
         *          This id is used when converting a {@link SummarizerConfiguration} to table
         *          properties. Since tables can have multiple summarizers, make sure its unique.
         *
         * @see SummarizerConfiguration#toTableProperties()
         */
        public Builder setPropertyId(String propId) {
            Preconditions.checkArgument(propId.matches("\\w+"), "Config Id %s is not alphanum", propId);
            this.configId = propId;
            return this;
        }

        /**
         * Adds an option that Summarizers can use when constructing Collectors and Combiners.
         *
         * @return this
         *
         * @see SummarizerConfiguration#getOptions()
         */
        public Builder addOption(String key, String value) {
            Preconditions.checkArgument(key.matches("\\w+"), "Option Id %s is not alphanum", key);
            imBuilder.put(key, value);
            return this;
        }

        /**
         * Adds an option that Summarizers can use when constructing Collectors and Combiners.
         *
         * @return this
         *
         * @see SummarizerConfiguration#getOptions()
         */
        public Builder addOption(String key, long value) {
            return addOption(key, Long.toString(value));
        }

        /**
         * Convenience method for adding multiple options. The following
         *
         * <pre>
         * {@code builder.addOptions("opt1","val1","opt2","val2","opt3","val3")}
         * </pre>
         *
         * <p>
         * is equivalent to
         *
         * <pre>
         * {@code
         *   builder.addOption("opt1","val1");
         *   builder.addOption("opt2","val2");
         *   builder.addOption("opt3","val3");
         * }
         * </pre>
         *
         * @param keyValuePairs
         *          This array must have an even and positive number of elements.
         * @return this
         * @see SummarizerConfiguration#getOptions()
         */
        public Builder addOptions(String... keyValuePairs) {
            Preconditions.checkArgument(keyValuePairs.length % 2 == 0 && keyValuePairs.length > 0,
                    "Require an even, positive number of arguments, got %s", keyValuePairs.length);
            for (int i = 1; i < keyValuePairs.length; i += 2) {
                addOption(keyValuePairs[i - 1], keyValuePairs[i]);
            }
            return this;
        }

        /**
         * @param options
         *          Each entry in the map is passed to {@link #addOption(String, String)}
         * @return this
         *
         * @see SummarizerConfiguration#getOptions()
         */
        public Builder addOptions(Map<String, String> options) {
            options.entrySet().forEach(e -> addOption(e.getKey(), e.getValue()));
            return this;
        }

        public SummarizerConfiguration build() {
            return new SummarizerConfiguration(className, configId, imBuilder.build());
        }
    }

    /**
     * Call this method to initiate a chain of fluent method calls to a create an immutable
     * {@link SummarizerConfiguration}
     *
     * @param className
     *          The fully qualified name of a class that implements {@link Summarizer}.
     */
    public static Builder builder(String className) {
        return new Builder(className);
    }

    /**
     * @see #builder(String)
     */
    public static Builder builder(Class<? extends Summarizer> clazz) {
        return new Builder(clazz.getName());
    }
}