/** * 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.relevance; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.browseengine.bobo.facets.RuntimeFacetHandler; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.json.JSONException; import org.json.JSONObject; 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.TermDoubleList; 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.TermShortList; import com.browseengine.bobo.facets.data.TermStringList; import com.browseengine.bobo.facets.data.TermValueList; import com.browseengine.bobo.util.BigSegmentedArray; import com.senseidb.indexing.activity.facet.ActivityRangeFacetHandler; import com.senseidb.search.query.ScoreAugmentQuery.ScoreAugmentFunction; import com.senseidb.search.relevance.impl.CompilationHelper; import com.senseidb.search.relevance.impl.CustomMathModel; import com.senseidb.search.relevance.impl.RelevanceJSONConstants; import com.senseidb.search.relevance.impl.MFacetDouble; import com.senseidb.search.relevance.impl.MFacetFloat; import com.senseidb.search.relevance.impl.MFacetInt; import com.senseidb.search.relevance.impl.MFacetLong; import com.senseidb.search.relevance.impl.MFacetShort; import com.senseidb.search.relevance.impl.MFacetString; import com.senseidb.search.relevance.impl.WeightedMFacetDouble; import com.senseidb.search.relevance.impl.WeightedMFacetFloat; import com.senseidb.search.relevance.impl.WeightedMFacetInt; import com.senseidb.search.relevance.impl.WeightedMFacetLong; import com.senseidb.search.relevance.impl.WeightedMFacetShort; import com.senseidb.search.relevance.impl.WeightedMFacetString; import com.senseidb.search.relevance.impl.CompilationHelper.DataTable; public class RuntimeRelevanceFunction extends CustomRelevanceFunction { private static Logger logger = Logger.getLogger(RuntimeRelevanceFunction.class); //per request shared data; private DataTable _dt; private CustomMathModel _cModel; //index reader level data; private BigSegmentedArray[] _orderArrays; private TermValueList[] _termLists; private MultiValueFacetDataCache[] _mDataCaches; private TermValueList[] _mTermLists; private ActivityRangeFacetHandler[] _aHandlers; private int[][] _aData; private int[] _types; private int[] _facetIndex; private int[] _arrayIndex; private int[] _mFacetIndex; private int[] _mArrayIndex; private int[] _aFacetIndex; private int _paramSize; private short[] shorts; private int[] ints; private long[] longs; private float[] floats; private double[] doubles; private boolean[] booleans; private String[] strings; private Set[] sets; private Map[] maps; private Object[] objs; private MFacetInt[] mFacetInts; private MFacetLong[] mFacetLongs; private MFacetShort[] mFacetShorts; private MFacetFloat[] mFacetFloats; private MFacetDouble[] mFacetDoubles; private MFacetString[] mFacetStrings; private RuntimeFacetHandler networkFacetHandler; private BoboIndexReader boboIndexReader; private int[] dynamicAR; private static final String NETWORK_FACET_NAME = "network"; private static final String NETWORK_TERMLIST_VALUE = "runtime-facet-network"; public RuntimeRelevanceFunction(CustomMathModel cModel, DataTable dt) { _cModel = cModel; _dt = dt; } private void initialRunningData(BoboIndexReader boboReader, CustomMathModel cModel, DataTable _dt) throws IOException { // (1) normal facet; int numFacet = _dt.hm_symbol_facet.keySet().size(); final BigSegmentedArray[] orderArrays = new BigSegmentedArray[numFacet]; final TermValueList[] termLists = new TermValueList[numFacet]; Iterator<String> iter_facet = _dt.hm_facet_index.keySet().iterator(); while(iter_facet.hasNext()){ String facetName = iter_facet.next(); int index = _dt.hm_facet_index.get(facetName); if(facetName.equalsIgnoreCase(NETWORK_FACET_NAME)) { try { networkFacetHandler = (RuntimeFacetHandler) boboReader.getFacetHandler(NETWORK_FACET_NAME); boboIndexReader = boboReader; TermStringList t = new TermStringList(); t.add(NETWORK_TERMLIST_VALUE); termLists[index] = t; } catch (Exception ex) { // Being safe to not affect other facets. logger.warn("Error getting network facet"); } continue; } // validation; Object dataObj = boboReader.getFacetData(facetName); if ( ! (dataObj instanceof FacetDataCache<?>)) throw new IllegalArgumentException("Facet " + facetName + " does not have a valid FacetDataCache."); orderArrays[index] = ((FacetDataCache)(boboReader.getFacetData(facetName))).orderArray; termLists[index] = ((FacetDataCache)(boboReader.getFacetData(facetName))).valArray; } // (2) multi-facet; int numMultiFacet = _dt.hm_symbol_mfacet.keySet().size(); final MultiValueFacetDataCache[] mDataCaches = new MultiValueFacetDataCache[numMultiFacet]; final TermValueList[] mTermLists = new TermValueList[numMultiFacet]; Iterator<String> iter_mfacet = _dt.hm_mfacet_index.keySet().iterator(); while(iter_mfacet.hasNext()){ String mFacetName = iter_mfacet.next(); // validation; Object dataObj = boboReader.getFacetData(mFacetName); if ( ! (dataObj instanceof FacetDataCache<?>)) throw new IllegalArgumentException("Facet " + mFacetName + " does not have a valid FacetDataCache."); int index = _dt.hm_mfacet_index.get(mFacetName); mDataCaches[index] = (MultiValueFacetDataCache)(boboReader.getFacetData(mFacetName)); mTermLists[index] = ((MultiValueFacetDataCache)(boboReader.getFacetData(mFacetName))).valArray; } // (3) activity engine facet; int numAFacet = _dt.hm_symbol_afacet.keySet().size(); final int[][] aData = new int[numAFacet][]; final ActivityRangeFacetHandler[] aHandlers = new ActivityRangeFacetHandler[numAFacet]; Iterator<String> iter_afacet = _dt.hm_afacet_index.keySet().iterator(); while(iter_afacet.hasNext()){ String afacetName = iter_afacet.next(); // validation; FacetHandler arHandler = boboReader.getFacetHandler(afacetName); Object dataObj = boboReader.getFacetData(afacetName); if( ! (dataObj instanceof int[])) throw new IllegalArgumentException("Facet " + afacetName + " does not have a valid FacetData for activity engine."); if(! (arHandler instanceof ActivityRangeFacetHandler)) throw new IllegalArgumentException("Facet " + afacetName + " is not an ActivityRangeFacetHandler."); int index = _dt.hm_afacet_index.get(afacetName); aData[index] = (int[])(boboReader.getFacetData(afacetName)); aHandlers[index] = (ActivityRangeFacetHandler) arHandler; } final int paramSize = _dt.lls_params.size(); final int[] types = new int[paramSize]; //store each parameter's type; final int[] facetIndex = new int[paramSize]; // if this parameter is a facet, what is its index number in the facet data array; final int[] arrayIndex = new int[paramSize]; // for each parameter, what is its index number in its own parameter array when passing into the function; final int[] mFacetIndex = new int[paramSize]; // if this parameter is a multi-facet, we need to know its index. Since we only use one array to store multi-facet, we do not need array index like the one for the simple facet; final int[] mArrayIndex = new int[paramSize]; // for each multi-facet, what is its index number in its own parameter array when passing into the function; final int[] aFacetIndex = new int[paramSize]; updateArrayIndex(_dt, paramSize, types, facetIndex, arrayIndex, mFacetIndex, mArrayIndex, aFacetIndex); _cModel = cModel; _orderArrays = orderArrays; _termLists = termLists; _types = types; _facetIndex = facetIndex; _arrayIndex = arrayIndex; _mDataCaches = mDataCaches; _mTermLists = mTermLists; _mFacetIndex = mFacetIndex; _mArrayIndex = mArrayIndex; _aHandlers = aHandlers; _aData = aData; _aFacetIndex = aFacetIndex; _paramSize = paramSize; shorts = new short[_paramSize]; ints = new int[_paramSize]; longs = new long[_paramSize]; floats = new float[_paramSize]; doubles = new double[_paramSize]; booleans = new boolean[_paramSize]; strings = new String[_paramSize]; sets = new Set[_paramSize]; maps = new Map[_paramSize]; objs = new Object[_paramSize]; mFacetInts = new MFacetInt[_paramSize]; mFacetLongs = new MFacetLong[_paramSize] ; mFacetShorts = new MFacetShort[_paramSize] ; mFacetFloats = new MFacetFloat[_paramSize]; mFacetDoubles = new MFacetDouble[_paramSize]; mFacetStrings = new MFacetString[_paramSize]; ArrayList<Integer> arDynamic = new ArrayList<Integer>(); // prepare the static variable; for(int i=0; i<_paramSize; i++) { switch (_types[i]) { // The static keyword variable initialization; case RelevanceJSONConstants.TYPENUMBER_NOW: longs[_arrayIndex[i]] = ((Long)_dt.hm_var.get(_dt.lls_params.get(i))).longValue(); break; // Normal variables; case RelevanceJSONConstants.TYPENUMBER_INT: ints[_arrayIndex[i]] = ((Integer)_dt.hm_var.get(_dt.lls_params.get(i))).intValue(); break; case RelevanceJSONConstants.TYPENUMBER_LONG: longs[_arrayIndex[i]] = ((Long)_dt.hm_var.get(_dt.lls_params.get(i))).longValue(); break; case RelevanceJSONConstants.TYPENUMBER_DOUBLE: doubles[_arrayIndex[i]] = ((Double)_dt.hm_var.get(_dt.lls_params.get(i))).doubleValue(); break; case RelevanceJSONConstants.TYPENUMBER_FLOAT: floats[_arrayIndex[i]] = ((Float)_dt.hm_var.get(_dt.lls_params.get(i))).floatValue(); break; case RelevanceJSONConstants.TYPENUMBER_BOOLEAN: booleans[_arrayIndex[i]] = ((Boolean)_dt.hm_var.get(_dt.lls_params.get(i))).booleanValue(); break; case RelevanceJSONConstants.TYPENUMBER_STRING: strings[_arrayIndex[i]] = (String) _dt.hm_var.get(_dt.lls_params.get(i)); break; case RelevanceJSONConstants.TYPENUMBER_SET: sets[_arrayIndex[i]] = (Set)_dt.hm_var.get(_dt.lls_params.get(i)); break; case RelevanceJSONConstants.TYPENUMBER_MAP: maps[_arrayIndex[i]] = (Map)_dt.hm_var.get(_dt.lls_params.get(i)); break; // Custom Object; case RelevanceJSONConstants.TYPENUMBER_CUSTOM_OBJ: objs[_arrayIndex[i]] = _dt.hm_var.get(_dt.lls_params.get(i)); break; // Multi-facet container initialization; case RelevanceJSONConstants.TYPENUMBER_FACET_M_INT: mFacetInts[_mArrayIndex[i]] = new MFacetInt(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_LONG: mFacetLongs[_mArrayIndex[i]] = new MFacetLong(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_DOUBLE: mFacetDoubles[_mArrayIndex[i]] = new MFacetDouble(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_FLOAT: mFacetFloats[_mArrayIndex[i]] = new MFacetFloat(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_SHORT: mFacetShorts[_mArrayIndex[i]] = new MFacetShort(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_STRING: mFacetStrings[_mArrayIndex[i]] = new MFacetString(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; // Weighted multi-facet container initialization; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_INT: mFacetInts[_mArrayIndex[i]] = new WeightedMFacetInt(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_LONG: mFacetLongs[_mArrayIndex[i]] = new WeightedMFacetLong(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_DOUBLE: mFacetDoubles[_mArrayIndex[i]] = new WeightedMFacetDouble(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_FLOAT: mFacetFloats[_mArrayIndex[i]] = new WeightedMFacetFloat(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_SHORT: mFacetShorts[_mArrayIndex[i]] = new WeightedMFacetShort(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_STRING: mFacetStrings[_mArrayIndex[i]] = new WeightedMFacetString(_mDataCaches[_mFacetIndex[i]]); arDynamic.add(i); break; default: arDynamic.add(i); } } dynamicAR = convertIntegers(arDynamic); } private int[] convertIntegers(List<Integer> integers) { int[] ret = new int[integers.size()]; Iterator<Integer> iterator = integers.iterator(); for (int i = 0; i < ret.length; i++) { ret[i] = iterator.next().intValue(); } return ret; } private void updateArrayIndex(DataTable _dt, int paramSize, int[] types, int[] facetIndex, int[] arrayIndex, int[] mFacetIndex, int[] mArrayIndex, int[] aFacetIndex) { int short_index = 0, m_short_index = 0; int int_index = 0, m_int_index = 0; int long_index = 0, m_long_index = 0; int float_index = 0, m_float_index = 0; int double_index = 0, m_double_index = 0; int string_index = 0, m_string_index = 0; int boolean_index = 0; int set_index = 0; int map_index = 0; int obj_index = 0; for(int i=0; i< paramSize; i++) { String symbol = _dt.lls_params.get(i); int typeNum = _dt.hm_type.get(symbol); types[i] = typeNum; String facetName = null; int index; switch (typeNum) { case RelevanceJSONConstants.TYPENUMBER_INNER_SCORE: arrayIndex[i] = float_index; float_index++; break; case RelevanceJSONConstants.TYPENUMBER_NOW: arrayIndex[i] = long_index; long_index++; break; case RelevanceJSONConstants.TYPENUMBER_CUSTOM_OBJ: arrayIndex[i] = obj_index; obj_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_INT: facetName = _dt.hm_symbol_facet.get(symbol); index = _dt.hm_facet_index.get(facetName); facetIndex[i] = index; // record the facet index; arrayIndex[i] = int_index; int_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_LONG: facetName = _dt.hm_symbol_facet.get(symbol); index = _dt.hm_facet_index.get(facetName); facetIndex[i] = index; // record the facet index; arrayIndex[i] = long_index; long_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_FLOAT: facetName = _dt.hm_symbol_facet.get(symbol); index = _dt.hm_facet_index.get(facetName); facetIndex[i] = index; // record the facet index; arrayIndex[i] = float_index; float_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_SHORT: facetName = _dt.hm_symbol_facet.get(symbol); index = _dt.hm_facet_index.get(facetName); facetIndex[i] = index; // record the facet index; arrayIndex[i] = short_index; short_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_STRING: facetName = _dt.hm_symbol_facet.get(symbol); index = _dt.hm_facet_index.get(facetName); facetIndex[i] = index; // record the facet index; arrayIndex[i] = string_index; string_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_A_INT: facetName = _dt.hm_symbol_afacet.get(symbol); index = _dt.hm_afacet_index.get(facetName); aFacetIndex[i] = index; // record the activity engine facet index; arrayIndex[i] = int_index; int_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_INT: case RelevanceJSONConstants.TYPENUMBER_FACET_WM_INT: facetName = _dt.hm_symbol_mfacet.get(symbol); index = _dt.hm_mfacet_index.get(facetName); mFacetIndex[i] = index; // record the multi-facet index; mArrayIndex[i] = m_int_index; m_int_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_LONG: case RelevanceJSONConstants.TYPENUMBER_FACET_WM_LONG: facetName = _dt.hm_symbol_mfacet.get(symbol); index = _dt.hm_mfacet_index.get(facetName); mFacetIndex[i] = index; // record the multi-facet index; mArrayIndex[i] = m_long_index; m_long_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_DOUBLE: case RelevanceJSONConstants.TYPENUMBER_FACET_WM_DOUBLE: facetName = _dt.hm_symbol_mfacet.get(symbol); index = _dt.hm_mfacet_index.get(facetName); mFacetIndex[i] = index; // record the multi-facet index; mArrayIndex[i] = m_double_index; m_double_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_FLOAT: case RelevanceJSONConstants.TYPENUMBER_FACET_WM_FLOAT: facetName = _dt.hm_symbol_mfacet.get(symbol); index = _dt.hm_mfacet_index.get(facetName); mFacetIndex[i] = index; // record the multi-facet index; mArrayIndex[i] = m_float_index; m_float_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_SHORT: case RelevanceJSONConstants.TYPENUMBER_FACET_WM_SHORT: facetName = _dt.hm_symbol_mfacet.get(symbol); index = _dt.hm_mfacet_index.get(facetName); mFacetIndex[i] = index; // record the multi-facet index; mArrayIndex[i] = m_short_index; m_short_index++; break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_STRING: case RelevanceJSONConstants.TYPENUMBER_FACET_WM_STRING: facetName = _dt.hm_symbol_mfacet.get(symbol); index = _dt.hm_mfacet_index.get(facetName); mFacetIndex[i] = index; // record the multi-facet index; mArrayIndex[i] = m_string_index; m_string_index++; break; case RelevanceJSONConstants.TYPENUMBER_INT: arrayIndex[i] = int_index; int_index++; break; case RelevanceJSONConstants.TYPENUMBER_LONG: arrayIndex[i] = long_index; long_index++; break; case RelevanceJSONConstants.TYPENUMBER_DOUBLE: arrayIndex[i] = double_index; double_index++; break; case RelevanceJSONConstants.TYPENUMBER_FLOAT: arrayIndex[i] = float_index; float_index++; break; case RelevanceJSONConstants.TYPENUMBER_BOOLEAN: arrayIndex[i] = boolean_index; boolean_index++; break; case RelevanceJSONConstants.TYPENUMBER_STRING: arrayIndex[i] = string_index; string_index++; break; case RelevanceJSONConstants.TYPENUMBER_SET_INT: case RelevanceJSONConstants.TYPENUMBER_SET_LONG: case RelevanceJSONConstants.TYPENUMBER_SET_DOUBLE: case RelevanceJSONConstants.TYPENUMBER_SET_FLOAT: case RelevanceJSONConstants.TYPENUMBER_SET_STRING: types[i] = RelevanceJSONConstants.TYPENUMBER_SET; arrayIndex[i] = set_index; set_index++; break; case RelevanceJSONConstants.TYPENUMBER_MAP_INT_INT: case RelevanceJSONConstants.TYPENUMBER_MAP_INT_LONG: case RelevanceJSONConstants.TYPENUMBER_MAP_INT_DOUBLE: case RelevanceJSONConstants.TYPENUMBER_MAP_INT_FLOAT: case RelevanceJSONConstants.TYPENUMBER_MAP_INT_STRING: case RelevanceJSONConstants.TYPENUMBER_MAP_STRING_INT: case RelevanceJSONConstants.TYPENUMBER_MAP_STRING_LONG: case RelevanceJSONConstants.TYPENUMBER_MAP_STRING_DOUBLE: case RelevanceJSONConstants.TYPENUMBER_MAP_STRING_FLOAT: case RelevanceJSONConstants.TYPENUMBER_MAP_STRING_STRING: types[i] = RelevanceJSONConstants.TYPENUMBER_MAP; arrayIndex[i] = map_index; map_index++; break; } } } @Override public float newScore(float innerScore, int docID){ //update the dynamic parameters only when we have to. for(int j=0; j < dynamicAR.length; j++) { // only when the parameter is inner score variable or facet variable, we need to update the score function input parameter arrays; switch (_types[dynamicAR[j]]) { case RelevanceJSONConstants.TYPENUMBER_INNER_SCORE: floats[_arrayIndex[dynamicAR[j]]] = innerScore; break; // normal facet; case RelevanceJSONConstants.TYPENUMBER_FACET_INT: if(_termLists[_facetIndex[dynamicAR[j]]] instanceof TermStringList) { //TO DO: Move this out to a method try { String runtimeParam = ((TermStringList)_termLists[_facetIndex[dynamicAR[j]]]).get(0); if(runtimeParam != null && runtimeParam.equals(NETWORK_TERMLIST_VALUE)) { String[] relationship = networkFacetHandler.getFieldValues(boboIndexReader, docID); if(relationship != null && relationship.length == 1) { ints[_arrayIndex[dynamicAR[j]]] = Integer.parseInt(relationship[0]); } } } catch(Exception ex) { logger.warn("Error populating network facet"); } } else { ints[_arrayIndex[dynamicAR[j]]] = ((TermIntList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); } break; case RelevanceJSONConstants.TYPENUMBER_FACET_LONG: longs[_arrayIndex[dynamicAR[j]]] = ((TermLongList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_DOUBLE: doubles[_arrayIndex[dynamicAR[j]]] = ((TermDoubleList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_FLOAT: floats[_arrayIndex[dynamicAR[j]]] = ((TermFloatList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_SHORT: shorts[_arrayIndex[dynamicAR[j]]] = ((TermShortList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_STRING: strings[_arrayIndex[dynamicAR[j]]] = ((TermStringList)_termLists[_facetIndex[dynamicAR[j]]]).get(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; // multi-facet below; case RelevanceJSONConstants.TYPENUMBER_FACET_M_INT: mFacetInts[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_LONG: mFacetLongs[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_DOUBLE: mFacetDoubles[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_FLOAT: mFacetFloats[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_SHORT: mFacetShorts[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_STRING: mFacetStrings[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; // weighted multi-facet below; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_INT: ((WeightedMFacetInt)mFacetInts[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_LONG: ((WeightedMFacetLong)mFacetLongs[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_DOUBLE: ((WeightedMFacetDouble)mFacetDoubles[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_FLOAT: ((WeightedMFacetFloat)mFacetFloats[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_SHORT: ((WeightedMFacetShort)mFacetShorts[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_STRING: ((WeightedMFacetString)mFacetStrings[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; // activity engine facet; case RelevanceJSONConstants.TYPENUMBER_FACET_A_INT: ints[_arrayIndex[dynamicAR[j]]] = _aHandlers[_aFacetIndex[dynamicAR[j]]].getIntActivityValue((int[])_aData[_aFacetIndex[dynamicAR[j]]], docID); break; default: break; } }// end for; return _cModel.score(shorts, ints, longs, floats, doubles, booleans, strings, sets, maps, mFacetInts, mFacetLongs, mFacetFloats, mFacetDoubles, mFacetShorts, mFacetStrings, objs); } @Override public float newScore(int docID) { //update the dynamic parameters only when we have to. for(int j=0; j < dynamicAR.length; j++) { // only when the parameter is inner score variable or facet variable, we need to update the score function input parameter arrays; switch (_types[dynamicAR[j]]) { case RelevanceJSONConstants.TYPENUMBER_FACET_INT: if(_termLists[_facetIndex[dynamicAR[j]]] instanceof TermStringList) { //TO DO: Move this out to a method try { String runtimeParam = ((TermStringList)_termLists[_facetIndex[dynamicAR[j]]]).get(0); if(runtimeParam != null && runtimeParam.equals(NETWORK_TERMLIST_VALUE)) { String[] relationship = networkFacetHandler.getFieldValues(boboIndexReader, docID); if(relationship != null && relationship.length == 1) { ints[_arrayIndex[dynamicAR[j]]] = Integer.parseInt(relationship[0]); } } } catch(Exception ex) { logger.warn("Error populating network facet"); } } else { ints[_arrayIndex[dynamicAR[j]]] = ((TermIntList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); } break; case RelevanceJSONConstants.TYPENUMBER_FACET_LONG: longs[_arrayIndex[dynamicAR[j]]] = ((TermLongList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_DOUBLE: doubles[_arrayIndex[dynamicAR[j]]] = ((TermDoubleList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_FLOAT: floats[_arrayIndex[dynamicAR[j]]] = ((TermFloatList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_SHORT: shorts[_arrayIndex[dynamicAR[j]]] = ((TermShortList)_termLists[_facetIndex[dynamicAR[j]]]).getPrimitiveValue(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; case RelevanceJSONConstants.TYPENUMBER_FACET_STRING: strings[_arrayIndex[dynamicAR[j]]] = ((TermStringList)_termLists[_facetIndex[dynamicAR[j]]]).get(_orderArrays[_facetIndex[dynamicAR[j]]].get(docID)); break; // multi-facet below; case RelevanceJSONConstants.TYPENUMBER_FACET_M_INT: mFacetInts[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_LONG: mFacetLongs[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_DOUBLE: mFacetDoubles[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_FLOAT: mFacetFloats[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_SHORT: mFacetShorts[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_M_STRING: mFacetStrings[_mArrayIndex[dynamicAR[j]]].refresh(docID); break; // weighted multi-facet below; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_INT: ((WeightedMFacetInt)mFacetInts[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_LONG: ((WeightedMFacetLong)mFacetLongs[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_DOUBLE: ((WeightedMFacetDouble)mFacetDoubles[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_FLOAT: ((WeightedMFacetFloat)mFacetFloats[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_SHORT: ((WeightedMFacetShort)mFacetShorts[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; case RelevanceJSONConstants.TYPENUMBER_FACET_WM_STRING: ((WeightedMFacetString)mFacetStrings[_mArrayIndex[dynamicAR[j]]]).refresh(docID); break; // activity engine facet; case RelevanceJSONConstants.TYPENUMBER_FACET_A_INT: ints[_arrayIndex[dynamicAR[j]]] = _aHandlers[_aFacetIndex[dynamicAR[j]]].getIntActivityValue((int[])_aData[_aFacetIndex[dynamicAR[j]]], docID); break; default: break; } }// end for; return _cModel.score(shorts, ints, longs, floats, doubles, booleans, strings, sets, maps, mFacetInts, mFacetLongs, mFacetFloats, mFacetDoubles, mFacetShorts, mFacetStrings, objs); } @Override public String getExplainString(float innerScore, int doc) { return _dt.funcBody; } @Override public void initializeReader(BoboIndexReader reader, JSONObject jsonParams) throws IOException { initialRunningData(reader,_cModel, _dt); } @Override public void initializeGlobal(JSONObject jsonValues) throws JSONException { CompilationHelper.initializeValues(jsonValues, _dt); } @Override public ScoreAugmentFunction getCopy() { return new RuntimeRelevanceFunction(this._cModel, this._dt); } @Override public boolean useInnerScore() { return this._dt.useInnerScore; } public static class RuntimeRelevanceFunctionFactory extends CustomRelevanceFunctionFactory{ RuntimeRelevanceFunction _rrf; public RuntimeRelevanceFunctionFactory(RuntimeRelevanceFunction rrf) { _rrf = rrf; } @Override public CustomRelevanceFunction build() { return (CustomRelevanceFunction) _rrf.getCopy(); } } }