com.datatorrent.lib.math.QuotientMap.java Source code

Java tutorial

Introduction

Here is the source code for com.datatorrent.lib.math.QuotientMap.java

Source

/*
 * Copyright (c) 2013 DataTorrent, Inc. ALL Rights Reserved.
 *
 * 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 com.datatorrent.lib.math;

import java.util.HashMap;
import java.util.Map;

import javax.validation.constraints.Min;

import com.datatorrent.api.annotation.OperatorAnnotation;
import org.apache.commons.lang.mutable.MutableDouble;

import com.datatorrent.api.DefaultInputPort;
import com.datatorrent.api.DefaultOutputPort;
import com.datatorrent.api.annotation.InputPortFieldAnnotation;
import com.datatorrent.api.annotation.OutputPortFieldAnnotation;
import com.datatorrent.lib.util.BaseNumberKeyValueOperator;

/**
 * Add all the values for each key on "numerator" and "denominator" and emits quotient at end of window for all keys in the denominator. 
 * <p>
 * <br>
 * Application can set multiplication value for quotient(default = 1). <br>
 * Operator will calculate quotient of occurrence of key in numerator divided by
 * occurrence of key in denominator if countKey flag is true. <br>
 * Application can allow or block keys by setting filter key and inverse flag. <br>
 * <br>
 * <b>StateFull : Yes</b>, numerator/denominator values are summed over
 * application window. <br>
 * <b>Partitions : No, </b>, will yield wrong results, since values are summed
 * over app window. <br>
 * <br>
 * <b>Ports</b>:<br>
 * <b>numerator</b>: expects Map&lt;K,V extends Number&gt;<br>
 * <b>denominator</b>: expects Map&lt;K,V extends Number&gt;<br>
 * <b>quotient</b>: emits HashMap&lt;K,Double&gt;<br>
 * <br>
 * <b>Properties</b>:<br>
 * <b>inverse :</b> if set to true the key in the filter will block tuple<br>
 * <b>filterBy :</b> List of keys to filter on<br>
 * <b>countkey :</b> Get quotient of occurrence of keys in numerator and
 * denominator. <br>
 * <b>mult_by :</b> Set multiply by constant value. <br>
 * <br>
 * @displayName Quotient Map
 * @category Math
 * @tags division, sum, map
 * @since 0.3.3
 */
@OperatorAnnotation(partitionable = false)
public class QuotientMap<K, V extends Number> extends BaseNumberKeyValueOperator<K, V> {
    /**
     * Numerator key/sum value map.
     */
    protected HashMap<K, MutableDouble> numerators = new HashMap<K, MutableDouble>();

    /**
     * Denominator key/sum value map.
     */
    protected HashMap<K, MutableDouble> denominators = new HashMap<K, MutableDouble>();

    /**
     * Count occurrence of keys if set to true.
     */
    boolean countkey = false;

    /**
     * Quotient multiply by value.
     */
    int mult_by = 1;

    /**
     * Numerator input port.
     */
    public final transient DefaultInputPort<Map<K, V>> numerator = new DefaultInputPort<Map<K, V>>() {
        /**
         * Added tuple to the numerator hash
         */
        @Override
        public void process(Map<K, V> tuple) {
            addTuple(tuple, numerators);
        }
    };

    /**
     * Denominator input port.
     */
    public final transient DefaultInputPort<Map<K, V>> denominator = new DefaultInputPort<Map<K, V>>() {
        /**
         * Added tuple to the denominator hash
         */
        @Override
        public void process(Map<K, V> tuple) {
            addTuple(tuple, denominators);
        }
    };

    /**
     * Quotient output port.
     */
    public final transient DefaultOutputPort<HashMap<K, Double>> quotient = new DefaultOutputPort<HashMap<K, Double>>();

    /**
     * Add tuple to nval/dval map.
     * 
     * @param tuple
     *          key/value map on input port.
     * @param map
     *          key/summed value map.
     */
    public void addTuple(Map<K, V> tuple, Map<K, MutableDouble> map) {
        for (Map.Entry<K, V> e : tuple.entrySet()) {
            addEntry(e.getKey(), e.getValue(), map);
        }
    }

    /**
     * Add/Update entry to key/sum value map.
     * 
     * @param key
     *          name.
     * @param value
     *          value for key.
     * @param map
     *          numerator/denominator key/sum map.
     */
    public void addEntry(K key, V value, Map<K, MutableDouble> map) {
        if (!doprocessKey(key) || (value == null)) {
            return;
        }
        MutableDouble val = map.get(key);
        if (val == null) {
            if (countkey) {
                val = new MutableDouble(1.00);
            } else {
                val = new MutableDouble(value.doubleValue());
            }
        } else {
            if (countkey) {
                val.increment();
            } else {
                val.add(value.doubleValue());
            }
        }
        map.put(cloneKey(key), val);
    }

    /**
     * getter for mult_by
     * 
     * @return mult_by
     */

    @Min(0)
    public int getMult_by() {
        return mult_by;
    }

    /**
     * getter for countkey
     * 
     * @return countkey
     */
    public boolean getCountkey() {
        return countkey;
    }

    /**
     * Setter for mult_by
     * 
     * @param i
     */
    public void setMult_by(int i) {
        mult_by = i;
    }

    /**
     * setter for countkey
     * 
     * @param i
     *          sets countkey
     */
    public void setCountkey(boolean i) {
        countkey = i;
    }

    /**
     * Generates tuples for each key and emits them. Only keys that are in the
     * denominator are iterated on If the key is only in the numerator, it gets
     * ignored (cannot do divide by 0) Clears internal data
     */
    @Override
    public void endWindow() {
        HashMap<K, Double> tuples = new HashMap<K, Double>();
        for (Map.Entry<K, MutableDouble> e : denominators.entrySet()) {
            MutableDouble nval = numerators.get(e.getKey());
            if (nval == null) {
                tuples.put(e.getKey(), new Double(0.0));
            } else {
                tuples.put(e.getKey(), new Double((nval.doubleValue() / e.getValue().doubleValue()) * mult_by));
            }
        }
        if (!tuples.isEmpty()) {
            quotient.emit(tuples);
        }
        numerators.clear();
        denominators.clear();
    }
}