Package com.inadco.hbl.model

Source Code of com.inadco.hbl.model.SimpleTimeHourHierarchy

/*
*
*  Copyright © 2010, 2011 Inadco, 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.inadco.hbl.model;

import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import org.apache.commons.lang.Validate;

import com.inadco.hbl.api.HierarchyMember;
import com.inadco.hbl.api.Range;
import com.inadco.hbl.client.HblException;
import com.inadco.hbl.client.impl.Slice;
import com.inadco.hbl.util.HblUtil;
import com.inadco.hbl.util.IOUtil;

/**
* standard time hierarchy supporting [ALL].[year-month].[date-hour] buckets.
* <P>
*
* I.e. the lowest granularity of a member bucket is hour.
* <P>
*
* @author dmitriy
*
*/
public class SimpleTimeHourHierarchy extends AbstractHierarchy {

    // so we organize key as [YYYYMM][DDHH] concatenated literals.
    // this, length=6+4=10

    private static final int      YM_KEYLEN               = 6;
    private static final int      DH_KEYLEN               = 4;
    private static final int      KEYLEN                  = YM_KEYLEN + DH_KEYLEN;
    private static final TimeZone UTC                     = TimeZone.getTimeZone("UTC");

    /*
     * if true, don't try to optimize time intervals with monthly key aggregates
     * and use all hourly keys only. In queries spanning from several months to
     * several years this yields significant improvement. The only reason to
     * switch it to true now is probably just to compare results between two
     * methods to debug current and future multilevel hierarchy optimizations.
     */
    private static final boolean  HOURLY_KEY_OPTIMIZATION = false;

    protected Object              nullkey;

    public SimpleTimeHourHierarchy(String name) {
        this(name, null);
    }

    public SimpleTimeHourHierarchy(String name, Object nullkey) {
        super(name, new String[] { "ALL", "year-month", "date-hour" });
        this.nullkey = nullkey == null ? null : IOUtil.tryClone(nullkey);
    }

    @Override
    public int getKeyLen() {
        return KEYLEN;
    }

    @Override
    public int getSubkeyLen(int level) {
        switch (level) {
        case 0:
            return 0;
        case 1:
            return YM_KEYLEN;
        case 2:
            return KEYLEN;
        default:
            Validate.isTrue(false, "invalid depth");
            return -1; // not reached
        }

    }

    @Override
    public void getKey(Object member, final byte[] buff, final int offset) {

        if (member == null) {
            member = nullkey;
        }

        if (member instanceof HierarchyMember) {
            HierarchyMember hm = (HierarchyMember) member;
            getKey(hm.getMember(), hm.getDepth(), buff, offset);
        } else {
            getKey(member, 2, buff, offset);
        }
    }

    @Override
    public void getKey(Object member, final int level, final byte[] buff, final int offset) {
        if (member == null) {
            member = nullkey;
            Validate.isTrue(member != null, "null is invalid member for a dimension member");
        }

        switch (level) {
        case 0:
            getAllKey(buff, offset);
            break;
        case 1:
            GregorianCalendar gcal = toGCal(member);
            getMonthlyKey(buff, offset, gcal);
            break;
        case 2:
            gcal = toGCal(member);
            getHourlyKey(buff, offset, gcal);
            break;
        default:
            Validate.isTrue(false, "invalid hierarchy depth");
        }
    }

    @Override
    public int getDepth() {
        return 3;
    }

    public void getAllKey(final byte[] buff, final int offset) {
        Arrays.fill(buff, offset, offset + KEYLEN, (byte) 0);
    }

    @Override
    public int keyDepth(byte[] buff, int offset) {
        if (buff[offset] == 0)
            return 0; // all-key
        if (buff[offset + 6] == 0)
            return 1; // monthly key
        return 2; // hourly key otherwise.
    }

    public void getMonthlyKey(byte[] buff, int offset, GregorianCalendar gcal) {
        HblUtil.fillCompositeKeyWithDec(gcal.get(Calendar.YEAR), 4, buff, offset);
        offset += 4;
        /* month field is 0-11 in GC */
        HblUtil.fillCompositeKeyWithDec(gcal.get(Calendar.MONTH) - Calendar.JANUARY + 1, 2, buff, offset);
        offset += 2;
        Arrays.fill(buff, offset, offset + DH_KEYLEN, (byte) 0);
    }

    public void getHourlyKey(byte[] buff, int offset, GregorianCalendar gcal) {
        HblUtil.fillCompositeKeyWithDec(gcal.get(Calendar.YEAR), 4, buff, offset);
        offset += 4;
        /* month field is 0-11 in GC */
        HblUtil.fillCompositeKeyWithDec(gcal.get(Calendar.MONTH) - Calendar.JANUARY + 1, 2, buff, offset);
        offset += 2;
        HblUtil.fillCompositeKeyWithDec(gcal.get(Calendar.DATE), 2, buff, offset);
        offset += 2;
        HblUtil.fillCompositeKeyWithDec(gcal.get(Calendar.HOUR_OF_DAY), 2, buff, offset);
    }

    @Override
    public Object getMember(byte[] buff, int offset) throws HblException {
        int depth = keyDepth(buff, offset);
        int year = 0;
        int month = 0;
        int date = 0;
        int hour = 0;

        switch (depth) {
        case 0:
            throw new HblException(
                "Unable to make a presentation of an [ALL] hierarchy member in terms of concrete calendar.");
        case 2:
            date = HblUtil.readCompositeKeyDec(buff, offset + 6, 2);
            hour = HblUtil.readCompositeKeyDec(buff, offset + 8, 2);
        case 1:
            year = HblUtil.readCompositeKeyDec(buff, offset, 4);
            month = HblUtil.readCompositeKeyDec(buff, offset + 4, 2) - Calendar.JANUARY + 1;
            break;
        default:
            throw new HblException("unexpected hierarchy depth in the key.");
        }
        // we return stuff as calendar objects here.
        GregorianCalendar gc = new GregorianCalendar(UTC);
        gc.set(Calendar.YEAR, year);
        gc.set(Calendar.MONTH, month);
        gc.set(Calendar.DATE, date);
        gc.set(Calendar.HOUR_OF_DAY, hour);
        gc.set(Calendar.MINUTE, 0);
        gc.set(Calendar.SECOND, 0);
        gc.set(Calendar.MILLISECOND, 0);
        return gc;

    }

    private static GregorianCalendar toGCal(Object member) {
        if (member instanceof GregorianCalendar) {
            GregorianCalendar gcal = new GregorianCalendar(UTC);
            gcal.setTimeInMillis(((GregorianCalendar) member).getTimeInMillis());
            return gcal;
        } else if (member instanceof Number) {
            // assume epoch milliseconds
            GregorianCalendar gcal = new GregorianCalendar(UTC);
            gcal.setTimeInMillis(((Number) member).longValue());
            return gcal;
        } else {
            Validate.isTrue(false, "Unsupported time hierarchy member object type");
            return null;
        }
    }

    @Override
    public Range[] optimizeSliceScan(Slice slice, boolean allowComplements) {
        if (HOURLY_KEY_OPTIMIZATION) {
            Range[] r = optimizeDimensionSliceScan(slice, allowComplements);
            r[0].setLevelOffset(YM_KEYLEN);
            r[0].setLevelLen(DH_KEYLEN);
            return r;
        } else
            return super.optimizeHierarchySliceScan(slice, allowComplements);
    }

}
TOP

Related Classes of com.inadco.hbl.model.SimpleTimeHourHierarchy

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.