/** * This software is licensed to you under the Apache License, Version 2.0 (the * "Apache License"). * * LinkedIn's contributions are made under the Apache License. If you contribute * to the Software, the contributions will be deemed to have been made under the * Apache License, unless you expressly indicate otherwise. Please do not make any * contributions that would be inconsistent with the Apache License. * * You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, this software * distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache * License for the specific language governing permissions and limitations for the * software governed under the Apache License. * * © 2012 LinkedIn Corp. All Rights Reserved. */ package com.senseidb.search.req.mapred; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import proj.zoie.api.DocIDMapper; import com.browseengine.bobo.api.BoboIndexReader; import com.browseengine.bobo.facets.FacetHandler; import com.browseengine.bobo.facets.data.FacetDataCache; import com.browseengine.bobo.facets.data.MultiValueFacetDataCache; import com.browseengine.bobo.facets.data.TermFloatList; import com.browseengine.bobo.facets.data.TermIntList; import com.browseengine.bobo.facets.data.TermLongList; import com.browseengine.bobo.facets.data.TermNumberList; import com.browseengine.bobo.facets.data.TermShortList; import com.browseengine.bobo.facets.data.TermValueList; import com.senseidb.search.req.SenseiSystemInfo.SenseiFacetInfo; /** * This class was designed to avoid polymorphism and to leverage primitive types as much as possible * It allows access to the facetted data * */ @SuppressWarnings("rawtypes") public final class FieldAccessor { private final Set<String> facets = new HashSet<String>(); private final BoboIndexReader boboIndexReader; private FacetDataCache lastFacetDataCache; private String lastFacetDataCacheName; private Map<String, FacetDataCache> facetDataMap = new HashMap<String, FacetDataCache>(); private final DocIDMapper mapper; public FieldAccessor(Set<SenseiFacetInfo> facetInfos, BoboIndexReader boboIndexReader, DocIDMapper mapper) { this.mapper = mapper; for (SenseiFacetInfo facetInfo : facetInfos) { facets.add(facetInfo.getName()); } this.boboIndexReader = boboIndexReader; } public final FacetDataCache getValueCache(String name) { if (name.equals(lastFacetDataCacheName)) { return lastFacetDataCache; } FacetDataCache ret = facetDataMap.get(name); if (ret != null) { lastFacetDataCache = ret; lastFacetDataCacheName = name; return ret; } Object rawFacetData = boboIndexReader.getFacetData(name); if (!(rawFacetData instanceof FacetDataCache)) { return null; } ret = (FacetDataCache) rawFacetData; facetDataMap.put(name, ret); return ret; } /** * Get facet value for the document * @param fieldName * @param docId * @return */ public final Object get(String fieldName, int docId) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache instanceof MultiValueFacetDataCache) { return getArray(fieldName, docId); } if (valueCache != null) { return valueCache.valArray.getRawValue(valueCache.orderArray.get(docId)); } return getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId); } /** * Get string facet value for the document * @param fieldName * @param docId * @return */ public final String getString(String fieldName, int docId) { return getFacetHandler(fieldName).getFieldValue(boboIndexReader, docId); } /** * Get long facet value for the document * @param fieldName * @param docId * @return */ public final long getLong(String fieldName, int docId) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache != null) { if (valueCache.valArray instanceof TermLongList) { return ((TermLongList) valueCache.valArray).getPrimitiveValue(valueCache.orderArray.get(docId)); } else { return (long)((TermNumberList) valueCache.valArray).getDoubleValue(valueCache.orderArray.get(docId)); } } else { Object value = getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId)[0]; if (value instanceof Long) { return (Long)value; } if (value instanceof Number) { return ((Number)value).longValue(); } if (value instanceof String) { return Long.parseLong((String)value); } throw new UnsupportedOperationException("Class " + value.getClass() + " can not be converted to long"); } } /** * Get double facet value for the document * @param fieldName * @param docId * @return */ public final double getDouble(String fieldName, int docId) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache != null) { return ((TermNumberList) valueCache.valArray).getDoubleValue(valueCache.orderArray.get(docId)); } else { Object value = getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId)[0]; if (value instanceof Double) { return (Double)value; } if (value instanceof Number) { return ((Number)value).doubleValue(); } if (value instanceof String) { return Double.parseDouble((String)value); } throw new UnsupportedOperationException("Class " + value.getClass() + " can not be converted to double"); } } /** * Get short facet value for the document * @param fieldName * @param docId * @return */ public final short getShort(String fieldName, int docId) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache != null) { if (valueCache.valArray instanceof TermShortList) { return ((TermShortList) valueCache.valArray).getPrimitiveValue(valueCache.orderArray.get(docId)); } else { return (short)((TermNumberList) valueCache.valArray).getDoubleValue(valueCache.orderArray.get(docId)); } } else { Object value = getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId)[0]; if (value instanceof Short) { return (Short)value; } if (value instanceof Number) { return ((Number)value).shortValue(); } if (value instanceof String) { return Short.parseShort((String)value); } throw new UnsupportedOperationException("Class " + value.getClass() + " can not be converted to short"); } } /** * Get integer facet value for the document * @param fieldName * @param docId * @return */ public final int getInteger(String fieldName, int docId) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache != null) { if (valueCache.valArray instanceof TermIntList) { return ((TermIntList) valueCache.valArray).getPrimitiveValue(valueCache.orderArray.get(docId)); } else { return (int)((TermNumberList) valueCache.valArray).getDoubleValue(valueCache.orderArray.get(docId)); } } else { Object value = getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId)[0]; if (value instanceof Integer) { return (Integer)value; } if (value instanceof Number) { return ((Number)value).intValue(); } if (value instanceof String) { return Integer.parseInt((String)value); } throw new UnsupportedOperationException("Class " + value.getClass() + " can not be converted to int"); } } /** * Get float facet value for the document * @param fieldName * @param docId * @return */ public final float getFloat(String fieldName, int docId) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache != null) { if (valueCache.valArray instanceof TermFloatList) { return ((TermFloatList) valueCache.valArray).getPrimitiveValue(valueCache.orderArray.get(docId)); } else { return (float)((TermNumberList) valueCache.valArray).getDoubleValue(valueCache.orderArray.get(docId)); } } else { Object value = getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId)[0]; if (value instanceof Float) { return (Float)value; } if (value instanceof Number) { return ((Number)value).floatValue(); } if (value instanceof String) { return Float.parseFloat((String)value); } throw new UnsupportedOperationException("Class " + value.getClass() + " can not be converted to float"); } } /** * Get array facet value for the document * @param fieldName * @param docId * @return */ public final Object[] getArray(String fieldName, int docId) { return getFacetHandler(fieldName).getRawFieldValues(boboIndexReader, docId); } public final Object getByUID(String fieldName, long uid) { return get(fieldName, mapper.quickGetDocID(uid)); } public final String getStringByUID(String fieldName, long uid) { return getString(fieldName, mapper.quickGetDocID(uid)); } public final long getLongByUID(String fieldName, long uid) { return getLong(fieldName, mapper.quickGetDocID(uid)); } public final double getDoubleByUID(String fieldName, long uid) { return getDouble(fieldName, mapper.quickGetDocID(uid)); } public final short getShortByUID(String fieldName, long uid) { return getShort(fieldName, mapper.quickGetDocID(uid)); } public final int getIntegerByUID(String fieldName, long uid) { return getInteger(fieldName, mapper.quickGetDocID(uid)); } public final float getFloatByUID(String fieldName, long uid) { return getFloat(fieldName, mapper.quickGetDocID(uid)); } public final Object[] getArrayByUID(String fieldName, long uid) { return getArray(fieldName, mapper.quickGetDocID(uid)); } public final TermValueList getTermValueList(String fieldName) { FacetDataCache valueCache = getValueCache(fieldName); if (valueCache == null) { return null; } return valueCache.valArray; } private String lastFacetHandlerName; private FacetHandler lastFacetHandler; /** * @param facetName * @return * @throws IllegalStateException if the facet can not be found */ public final FacetHandler getFacetHandler(String facetName) { if (!facetName.equals(lastFacetHandlerName)) { lastFacetHandler = boboIndexReader.getFacetHandler(facetName); lastFacetHandlerName = facetName; } if (lastFacetHandler == null) { throw new IllegalStateException("The facetHandler - " + facetName + " is not defined in the schema"); } return lastFacetHandler; } public BoboIndexReader getBoboIndexReader() { return boboIndexReader; } /** * Returns the docIdtoUID mapper * @return */ public DocIDMapper getMapper() { return mapper; } }