/** * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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 jp.co.yahoo.dataplatform.mds.hadoop.hive; import java.io.IOException; import java.util.Map; import java.util.HashMap; import org.apache.hadoop.hive.serde2.typeinfo.MapTypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.UnionTypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.SettableMapObjectInspector; import jp.co.yahoo.dataplatform.mds.spread.column.IColumn; import jp.co.yahoo.dataplatform.mds.hadoop.hive.io.ColumnAndIndex; import jp.co.yahoo.dataplatform.mds.hadoop.hive.io.PrimitiveToWritableConverter; public class MDSMapObjectInspector implements SettableMapObjectInspector{ private final StringObjectInspector keyObjectInspector; private final ObjectInspector valueObjectInspector; private final IGetField getField; public MDSMapObjectInspector( final MapTypeInfo typeInfo ){ TypeInfo keyTypeInfo = typeInfo.getMapKeyTypeInfo(); if( keyTypeInfo.getCategory() == ObjectInspector.Category.PRIMITIVE && ( (PrimitiveTypeInfo)keyTypeInfo ).getPrimitiveCategory() == PrimitiveCategory.STRING ){ keyObjectInspector = PrimitiveObjectInspectorFactory.javaStringObjectInspector; } else{ throw new RuntimeException( "Map key type is string only." ); } valueObjectInspector = MDSObjectInspectorFactory.craeteObjectInspectorFromTypeInfo( typeInfo.getMapValueTypeInfo() ); if( valueObjectInspector.getCategory() == ObjectInspector.Category.PRIMITIVE ){ getField = new PrimitiveGetField( (PrimitiveObjectInspector)valueObjectInspector ); } else if( valueObjectInspector.getCategory() == ObjectInspector.Category.UNION ){ getField = new UnionGetField( (UnionTypeInfo)( typeInfo.getMapValueTypeInfo() ) ); } else{ getField = new NestedGetField(); } } private interface IGetField{ public Object get( final IColumn childColumn , final int index , final int columnIndex ); } private static class PrimitiveGetField implements IGetField{ private final PrimitiveObjectInspector inspector; public PrimitiveGetField( final PrimitiveObjectInspector inspector ){ this.inspector = inspector; } @Override public Object get( final IColumn childColumn , final int index , final int columnIndex ){ try{ return PrimitiveToWritableConverter.convert( inspector.getPrimitiveCategory() , childColumn.get( index ) ); }catch( IOException e ){ throw new RuntimeException( e ); } } } private static class NestedGetField implements IGetField{ @Override public Object get( final IColumn childColumn , final int index , final int columnIndex ){ return new ColumnAndIndex( childColumn , index , columnIndex ); } } private static class UnionGetField implements IGetField{ private final UnionField unionField; public UnionGetField( final UnionTypeInfo unionTypeInfo ){ unionField = new UnionField( unionTypeInfo ); } @Override public Object get( final IColumn childColumn , final int index , final int columnIndex ){ return unionField.get( new ColumnAndIndex( childColumn , index , columnIndex ) ); } } @Override public ObjectInspector getMapKeyObjectInspector(){ return keyObjectInspector; } @Override public ObjectInspector getMapValueObjectInspector(){ return valueObjectInspector; } @Override public Object getMapValueElement( final Object object, final Object key ){ if( object instanceof ColumnAndIndex ){ ColumnAndIndex columnAndIndex = (ColumnAndIndex) object; IColumn childColumn = columnAndIndex.column.getColumn( key.toString() ); return getField.get( childColumn , columnAndIndex.index , columnAndIndex.columnIndex ); } else{ Map map = (Map)object; return map.get( key.toString() ); } } @Override public Map<?, ?> getMap( final Object object ){ if( object instanceof ColumnAndIndex ){ ColumnAndIndex columnAndIndex = (ColumnAndIndex) object; int childColumnSize = columnAndIndex.column.getColumnSize(); Map<Object,Object> result = new HashMap<Object, Object>( childColumnSize ); for( int i = 0 ; i < childColumnSize ; i++ ){ IColumn childColumn = columnAndIndex.column.getColumn(i); result.put( childColumn.getColumnName() , getField.get( childColumn , columnAndIndex.index , columnAndIndex.columnIndex ) ); } return result; } else{ return (Map<?,?>)object; } } @Override public int getMapSize( final Object object ){ return ((Map)object).size(); } @Override public String getTypeName() { StringBuilder buffer = new StringBuilder(); buffer.append("map<"); buffer.append( keyObjectInspector.getTypeName() ); buffer.append(","); buffer.append( valueObjectInspector.getTypeName() ); buffer.append(">"); return buffer.toString(); } @Override public Category getCategory(){ return Category.MAP; } @Override public Object create(){ return new HashMap<Object, Object>(); } @Override public Object put( final Object map, final Object key, final Object value ){ ( (Map<Object, Object>)map ).put( key, value ); return map; } @Override public Object remove( final Object map , final Object key ){ ( (Map<Object, Object>)map ).remove(key); return map; } @Override public Object clear( final Object map ){ ( (Map<Object, Object>)map ).clear(); return map; } }