io.druid.segment.QueryableIndexIndexableAdapter.java Source code

Java tutorial

Introduction

Here is the source code for io.druid.segment.QueryableIndexIndexableAdapter.java

Source

/*
* Licensed to Metamarkets Group Inc. (Metamarkets) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Metamarkets 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 io.druid.segment;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.metamx.common.ISE;
import com.metamx.common.guava.CloseQuietly;
import com.metamx.common.logger.Logger;
import io.druid.segment.column.BitmapIndex;
import io.druid.segment.column.Column;
import io.druid.segment.column.ColumnCapabilities;
import io.druid.segment.column.ComplexColumn;
import io.druid.segment.column.DictionaryEncodedColumn;
import io.druid.segment.column.GenericColumn;
import io.druid.segment.column.IndexedFloatsGenericColumn;
import io.druid.segment.column.IndexedLongsGenericColumn;
import io.druid.segment.column.ValueType;
import io.druid.segment.data.ArrayBasedIndexedInts;
import io.druid.segment.data.BitmapCompressedIndexedInts;
import io.druid.segment.data.EmptyIndexedInts;
import io.druid.segment.data.Indexed;
import io.druid.segment.data.IndexedInts;
import io.druid.segment.data.IndexedIterable;
import io.druid.segment.data.ListIndexed;
import org.joda.time.Interval;

import java.io.Closeable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 */
public class QueryableIndexIndexableAdapter implements IndexableAdapter {
    private static final Logger log = new Logger(QueryableIndexIndexableAdapter.class);
    private final int numRows;
    private final QueryableIndex input;
    private final List<String> availableDimensions;

    public QueryableIndexIndexableAdapter(QueryableIndex input) {
        this.input = input;
        numRows = input.getNumRows();

        // It appears possible that the dimensions have some columns listed which do not have a DictionaryEncodedColumn
        // This breaks current logic, but should be fine going forward.  This is a work-around to make things work
        // in the current state.  This code shouldn't be needed once github tracker issue #55 is finished.
        this.availableDimensions = Lists.newArrayList();
        for (String dim : input.getAvailableDimensions()) {
            final Column col = input.getColumn(dim);

            if (col == null) {
                log.warn("Wtf!? column[%s] didn't exist!?!?!?", dim);
            } else if (col.getDictionaryEncoding() != null) {
                availableDimensions.add(dim);
            } else {
                log.info("No dictionary on dimension[%s]", dim);
            }
        }
    }

    @Override
    public Interval getDataInterval() {
        return input.getDataInterval();
    }

    @Override
    public int getNumRows() {
        return numRows;
    }

    @Override
    public Indexed<String> getDimensionNames() {
        return new ListIndexed<>(availableDimensions, String.class);
    }

    @Override
    public Indexed<String> getMetricNames() {
        final Set<String> columns = Sets.newLinkedHashSet(input.getColumnNames());
        final HashSet<String> dimensions = Sets.newHashSet(getDimensionNames());

        return new ListIndexed<>(Lists.newArrayList(Sets.difference(columns, dimensions)), String.class);
    }

    @Override
    public Indexed<String> getDimValueLookup(String dimension) {
        final Column column = input.getColumn(dimension);

        if (column == null) {
            return null;
        }

        final DictionaryEncodedColumn dict = column.getDictionaryEncoding();

        if (dict == null) {
            return null;
        }

        return new Indexed<String>() {
            @Override
            public Class<? extends String> getClazz() {
                return String.class;
            }

            @Override
            public int size() {
                return dict.getCardinality();
            }

            @Override
            public String get(int index) {
                return dict.lookupName(index);
            }

            @Override
            public int indexOf(String value) {
                return dict.lookupId(value);
            }

            @Override
            public Iterator<String> iterator() {
                return IndexedIterable.create(this).iterator();
            }
        };
    }

    @Override
    public Iterable<Rowboat> getRows() {
        return new Iterable<Rowboat>() {
            @Override
            public Iterator<Rowboat> iterator() {
                return new Iterator<Rowboat>() {
                    final GenericColumn timestamps = input.getColumn(Column.TIME_COLUMN_NAME).getGenericColumn();
                    final Object[] metrics;

                    final DictionaryEncodedColumn[] dictionaryEncodedColumns;

                    final int numMetrics = getMetricNames().size();

                    int currRow = 0;
                    boolean done = false;

                    {
                        this.dictionaryEncodedColumns = FluentIterable.from(getDimensionNames())
                                .transform(new Function<String, DictionaryEncodedColumn>() {
                                    @Override
                                    public DictionaryEncodedColumn apply(String dimName) {
                                        return input.getColumn(dimName).getDictionaryEncoding();
                                    }
                                }).toArray(DictionaryEncodedColumn.class);

                        final Indexed<String> availableMetrics = getMetricNames();
                        metrics = new Object[availableMetrics.size()];
                        for (int i = 0; i < metrics.length; ++i) {
                            final Column column = input.getColumn(availableMetrics.get(i));
                            final ValueType type = column.getCapabilities().getType();
                            switch (type) {
                            case FLOAT:
                            case LONG:
                                metrics[i] = column.getGenericColumn();
                                break;
                            case COMPLEX:
                                metrics[i] = column.getComplexColumn();
                                break;
                            default:
                                throw new ISE("Cannot handle type[%s]", type);
                            }
                        }
                    }

                    @Override
                    public boolean hasNext() {
                        final boolean hasNext = currRow < numRows;
                        if (!hasNext && !done) {
                            CloseQuietly.close(timestamps);
                            for (Object metric : metrics) {
                                if (metric instanceof Closeable) {
                                    CloseQuietly.close((Closeable) metric);
                                }
                            }
                            for (Object dimension : dictionaryEncodedColumns) {
                                if (dimension instanceof Closeable) {
                                    CloseQuietly.close((Closeable) dimension);
                                }
                            }
                            done = true;
                        }
                        return hasNext;
                    }

                    @Override
                    public Rowboat next() {
                        if (!hasNext()) {
                            throw new NoSuchElementException();
                        }

                        final int[][] dims = new int[dictionaryEncodedColumns.length][];
                        int dimIndex = 0;
                        for (final DictionaryEncodedColumn dict : dictionaryEncodedColumns) {
                            final IndexedInts dimVals;
                            if (dict.hasMultipleValues()) {
                                dimVals = dict.getMultiValueRow(currRow);
                            } else {
                                dimVals = new ArrayBasedIndexedInts(new int[] { dict.getSingleValueRow(currRow) });
                            }

                            int[] theVals = new int[dimVals.size()];
                            for (int j = 0; j < theVals.length; ++j) {
                                theVals[j] = dimVals.get(j);
                            }

                            dims[dimIndex++] = theVals;
                        }

                        Object[] metricArray = new Object[numMetrics];
                        for (int i = 0; i < metricArray.length; ++i) {
                            if (metrics[i] instanceof IndexedFloatsGenericColumn) {
                                metricArray[i] = ((GenericColumn) metrics[i]).getFloatSingleValueRow(currRow);
                            } else if (metrics[i] instanceof IndexedLongsGenericColumn) {
                                metricArray[i] = ((GenericColumn) metrics[i]).getLongSingleValueRow(currRow);
                            } else if (metrics[i] instanceof ComplexColumn) {
                                metricArray[i] = ((ComplexColumn) metrics[i]).getRowValue(currRow);
                            }
                        }

                        final Rowboat retVal = new Rowboat(timestamps.getLongSingleValueRow(currRow), dims,
                                metricArray, currRow);

                        ++currRow;

                        return retVal;
                    }

                    @Override
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }

    @Override
    public IndexedInts getBitmapIndex(String dimension, String value) {
        final Column column = input.getColumn(dimension);

        if (column == null) {
            return new EmptyIndexedInts();
        }

        final BitmapIndex bitmaps = column.getBitmapIndex();
        if (bitmaps == null) {
            return new EmptyIndexedInts();
        }

        return new BitmapCompressedIndexedInts(bitmaps.getBitmap(value));
    }

    @Override
    public String getMetricType(String metric) {
        final Column column = input.getColumn(metric);

        final ValueType type = column.getCapabilities().getType();
        switch (type) {
        case FLOAT:
            return "float";
        case LONG:
            return "long";
        case COMPLEX:
            return column.getComplexColumn().getTypeName();
        default:
            throw new ISE("Unknown type[%s]", type);
        }
    }

    @Override
    public ColumnCapabilities getCapabilities(String column) {
        return input.getColumn(column).getCapabilities();
    }
}