Package com.senseidb.servlet

Source Code of com.senseidb.servlet.DefaultSenseiJSONServlet

/**
* 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.servlet;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.DataConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.SortField;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.browseengine.bobo.api.BrowseFacet;
import com.browseengine.bobo.api.BrowseHit;
import com.browseengine.bobo.api.BrowseSelection;
import com.browseengine.bobo.api.BrowseSelection.ValueOperation;
import com.browseengine.bobo.api.FacetAccessible;
import com.browseengine.bobo.api.FacetSpec;
import com.browseengine.bobo.api.FacetSpec.FacetSortSpec;
import com.browseengine.bobo.facets.DefaultFacetHandlerInitializerParam;
import com.senseidb.search.req.SenseiError;
import com.senseidb.search.req.SenseiHit;
import com.senseidb.search.req.SenseiJSONQuery;
import com.senseidb.search.req.SenseiQuery;
import com.senseidb.search.req.SenseiRequest;
import com.senseidb.search.req.SenseiResult;
import com.senseidb.search.req.SenseiSystemInfo;
import com.senseidb.util.JSONUtil.FastJSONArray;
import com.senseidb.util.JSONUtil.FastJSONObject;
import com.senseidb.util.RequestConverter;

import static com.senseidb.servlet.SenseiSearchServletParams.*;


public class DefaultSenseiJSONServlet extends AbstractSenseiRestServlet
{

  private static final String PARAM_RESULT_MAP_REDUCE = "mapReduceResult";

  /**
   *
   */
  private static final long serialVersionUID = 1L;

  private static Logger logger = Logger.getLogger(DefaultSenseiJSONServlet.class);

  public static JSONObject convertExpl(Explanation expl)
      throws JSONException
  {
    JSONObject jsonObject = null;
    if (expl != null)
    {
      jsonObject = new FastJSONObject(5);
      jsonObject.put(PARAM_RESULT_HITS_EXPL_VALUE, expl.getValue());
      String descr = expl.getDescription();
      jsonObject.put(PARAM_RESULT_HITS_EXPL_DESC, descr == null ? "" : descr);
      Explanation[] details = expl.getDetails();
      if (details != null)
      {
        JSONArray detailArray = new FastJSONArray(details.length);
        for (Explanation detail : details)
        {
          JSONObject subObj = convertExpl(detail);
          if (subObj != null)
          {
            detailArray.put(subObj);
          }
        }
        jsonObject.put(PARAM_RESULT_HITS_EXPL_DETAILS, detailArray);
      }
    }

    return jsonObject;
  }

  public static JSONObject convert(Map<String, FacetAccessible> facetValueMap, SenseiRequest req)
      throws JSONException
  {
    JSONObject resMap = new FastJSONObject(25);
    if (facetValueMap != null)
    {
      Set<Entry<String, FacetAccessible>> entrySet = facetValueMap.entrySet();

      for (Entry<String, FacetAccessible> entry : entrySet)
      {
        String fieldname = entry.getKey();

        BrowseSelection sel = req.getSelection(fieldname);
        HashSet<String> selectedVals = new HashSet<String>();
        if (sel != null)
        {
          String[] vals = sel.getValues();
          if (vals != null && vals.length > 0)
          {
            selectedVals.addAll(Arrays.asList(vals));
          }
        }

        FacetAccessible facetAccessible = entry.getValue();
        List<BrowseFacet> facetList = facetAccessible.getFacets();

        ArrayList<JSONObject> facets = new ArrayList<JSONObject>();

        for (BrowseFacet f : facetList)
        {
          String fval = f.getValue();
          if (fval != null && fval.length() > 0)
          {
            JSONObject fv = new FastJSONObject();
            fv.put(PARAM_RESULT_FACET_INFO_COUNT, f.getFacetValueHitCount());
            fv.put(PARAM_RESULT_FACET_INFO_VALUE, fval);
            fv.put(PARAM_RESULT_FACET_INFO_SELECTED, selectedVals.remove(fval));
            facets.add(fv);
          }
        }

        if (selectedVals.size() > 0)
        {
          // selected vals did not make it in top n
          for (String selectedVal : selectedVals)
          {
            if (selectedVal != null && selectedVal.length() > 0)
            {
              BrowseFacet selectedFacetVal = facetAccessible.getFacet(selectedVal);
              JSONObject fv = new FastJSONObject(5);
              fv.put(PARAM_RESULT_FACET_INFO_COUNT, selectedFacetVal == null ? 0 : selectedFacetVal.getFacetValueHitCount());
              String fval = selectedFacetVal == null ? selectedVal : selectedFacetVal.getValue();
              fv.put(PARAM_RESULT_FACET_INFO_VALUE, fval);
              fv.put(PARAM_RESULT_FACET_INFO_SELECTED, true);
              facets.add(fv);
            }
          }

          // we need to sort it
          FacetSpec fspec = req.getFacetSpec(fieldname);
          assert fspec != null;
          sortFacets(fieldname, facets, fspec);
        }

        resMap.put(fieldname, facets);
      }
    }
    return resMap;
  }

  private static void sortFacets(String fieldName, ArrayList<JSONObject> facets, FacetSpec fspec) {
    FacetSortSpec sortSpec = fspec.getOrderBy();
    if (FacetSortSpec.OrderHitsDesc.equals(sortSpec))
    {
      Collections.sort(facets, new Comparator<JSONObject>()
      {
        @Override
        public int compare(JSONObject o1, JSONObject o2)
        {
          try
          {
            int c1 = o1.getInt(PARAM_RESULT_FACET_INFO_COUNT);
            int c2 = o2.getInt(PARAM_RESULT_FACET_INFO_COUNT);
            int val = c2 - c1;
            if (val == 0)
            {
              String s1 = o1.getString(PARAM_RESULT_FACET_INFO_VALUE);
              String s2 = o1.getString(PARAM_RESULT_FACET_INFO_VALUE);
              val = s1.compareTo(s2);
            }
            return val;
          }
          catch (Exception e)
          {
            logger.error(e.getMessage(), e);
            return 0;
          }
        }
      });
    }
    else if (FacetSortSpec.OrderValueAsc.equals(sortSpec))
    {
      Collections.sort(facets, new Comparator<JSONObject>()
      {
        @Override
        public int compare(JSONObject o1, JSONObject o2)
        {
          try
          {
            String s1 = o1.getString(PARAM_RESULT_FACET_INFO_VALUE);
            String s2 = o1.getString(PARAM_RESULT_FACET_INFO_VALUE);
            return s1.compareTo(s2);
          }
          catch (Exception e)
          {
            logger.error(e.getMessage(), e);
            return 0;
          }
        }
      });
    }
    else
    {
      throw new IllegalStateException(fieldName + " sorting is not supported");
    }
  }

  @Override
  protected String buildResultString(HttpServletRequest httpReq, SenseiRequest req, SenseiResult res)
      throws Exception
  {
    return supportJsonp(httpReq, buildJSONResultString(req, res));
  }

  private String supportJsonp(HttpServletRequest httpReq, String jsonString) {
    String callback = httpReq.getParameter("callback");
    if (callback != null) {
      return callback + "(" + jsonString + ");";
    } else {
      return jsonString;
    }  
  }

  public static String buildJSONResultString(SenseiRequest req, SenseiResult res)
      throws Exception
  {
    JSONObject jsonObj = buildJSONResult(req, res);
    return jsonObj.toString();
  }

  public static JSONArray buildJSONHits(SenseiRequest req, SenseiHit[] hits)
      throws Exception
  {
    Set<String> selectSet = req.getSelectSet();

    JSONArray hitArray = new FastJSONArray(hits.length);
    for (SenseiHit hit : hits)
    {
      Map<String, String[]> fieldMap = hit.getFieldValues();
      int fieldMapSize = fieldMap == null ? 0 : fieldMap.size();

      JSONObject hitObj = new FastJSONObject(20 + fieldMapSize);

      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_UID))
      {
        hitObj.put(PARAM_RESULT_HIT_UID, hit.getUID());
      }
      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_DOCID))
      {
        hitObj.put(PARAM_RESULT_HIT_DOCID, hit.getDocid());
      }
      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_SCORE))
      {
        hitObj.put(PARAM_RESULT_HIT_SCORE, formatScore(req.getScoreMeaningfulDigits(), hit.getScore()));
      }
      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_GROUPFIELD))
      {
        hitObj.put(PARAM_RESULT_HIT_GROUPFIELD, hit.getGroupField());
      }
      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_GROUPVALUE))
      {
        hitObj.put(PARAM_RESULT_HIT_GROUPVALUE, hit.getGroupValue());
      }
      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_GROUPHITSCOUNT))
      {
        hitObj.put(PARAM_RESULT_HIT_GROUPHITSCOUNT, hit.getGroupHitsCount());
      }
      if (hit.getGroupHits() != null && hit.getGroupHits().length > 0)
        hitObj.put(PARAM_RESULT_HIT_GROUPHITS, buildJSONHits(req, hit.getSenseiGroupHits()));

      // get fetchStored even if request does not have it because it could be set at the
      // federated broker level
      if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_SRC_DATA) ||
          req.isFetchStoredFields() || hit.getSrcData() != null)
      {
        hitObj.put(PARAM_RESULT_HIT_SRC_DATA, hit.getSrcData());
      }
      if (fieldMap != null)
      {
        Set<Entry<String, String[]>> entries = fieldMap.entrySet();
        for (Entry<String, String[]> entry : entries)
        {
          String key = entry.getKey();
          if (key.equals(PARAM_RESULT_HIT_UID))
          {
            // UID is already set.
            continue;
          }

          if (selectSet == null || selectSet.contains(key))
          {
            String[] vals = entry.getValue();

            JSONArray valArray;
            if (vals != null)
            {
              valArray = new FastJSONArray(vals.length);
              for (String val : vals)
              {
                valArray.put(val);
              }
            }
            else
            {
              valArray = new FastJSONArray();
            }
            hitObj.put(key, valArray);
          }
        }
      }

      Document doc = hit.getStoredFields();
      if (doc != null)
      {
        if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_STORED_FIELDS))
        {
          List<Fieldable> fields = doc.getFields();
          List<JSONObject> storedData = new ArrayList<JSONObject>(fields.size());
          for (Fieldable field : fields)
          {
            JSONObject data = new FastJSONObject(4);
            data.put(PARAM_RESULT_HIT_STORED_FIELDS_NAME, field.name());
            data.put(PARAM_RESULT_HIT_STORED_FIELDS_VALUE, field.stringValue());
            storedData.add(data);
          }

          hitObj.put(PARAM_RESULT_HIT_STORED_FIELDS, new FastJSONArray(storedData));
        }
      }

      Map<String,BrowseHit.TermFrequencyVector> tvMap = hit.getTermFreqMap();
      if (tvMap != null && tvMap.size() > 0){
        JSONObject tvObj = new FastJSONObject(2 * tvMap.entrySet().size());
        if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_TERMVECTORS))
        {
          hitObj.put(PARAM_RESULT_HIT_TERMVECTORS, tvObj);
        }

        Set<Entry<String,BrowseHit.TermFrequencyVector>> entries = tvMap.entrySet();
        for (Entry<String,BrowseHit.TermFrequencyVector> entry : entries){
          String field = entry.getKey();

          String[] terms = entry.getValue().terms;
          int[] freqs = entry.getValue().freqs;

          JSONArray tvArray = new FastJSONArray(terms.length);
          for (int i=0;i<terms.length;++i){
            JSONObject tv = new FastJSONObject(4);
            tv.put("term", terms[i]);
            tv.put("freq", freqs[i]);
            tvArray.put(tv);
          }

          tvObj.put(field, tvArray);
        }
      }

      Explanation expl = hit.getExplanation();
      if (expl != null)
      {
        if (selectSet == null || selectSet.contains(PARAM_RESULT_HIT_EXPLANATION))
        {
          hitObj.put(PARAM_RESULT_HIT_EXPLANATION, convertExpl(expl));
        }
      }

      float [] features = hit.getFeatures();
      if (features != null)
      {
        JSONArray featureArray = new FastJSONArray(features.length);
        for (float f : features)
        {
          featureArray.put(f);
        }

        hitObj.put(PARAM_RESULT_FEATURES, featureArray);
      }

      hitArray.put(hitObj);
    }
    return hitArray;
  }

  public static JSONObject buildJSONResult(SenseiRequest req, SenseiResult res)
      throws Exception
  {
    JSONObject jsonObj = new FastJSONObject(15);
    jsonObj.put(PARAM_RESULT_TID, res.getTid());
    jsonObj.put(PARAM_RESULT_TOTALDOCS, res.getTotalDocs());
    jsonObj.put(PARAM_RESULT_NUMHITS, res.getNumHits());
    jsonObj.put(PARAM_RESULT_NUMGROUPS, res.getNumGroups());
    jsonObj.put(PARAM_RESULT_PARSEDQUERY, res.getParsedQuery());
    addErrors(jsonObj, res);
    SenseiHit[] hits = res.getSenseiHits();
    JSONArray hitArray = buildJSONHits(req, hits);
    jsonObj.put(PARAM_RESULT_HITS, hitArray);

    List<String> selectList = req.getSelectList();
    if (selectList != null)
    {
      JSONArray jsonSelectList = new FastJSONArray(selectList.size());
      for (String col: selectList)
      {
        jsonSelectList.put(col);
      }
      jsonObj.put(PARAM_RESULT_SELECT_LIST, jsonSelectList);
    }

    jsonObj.put(PARAM_RESULT_TIME, res.getTime());
    jsonObj.put(PARAM_RESULT_FACETS, convert(res.getFacetMap(), req));
    if (req.getMapReduceFunction() != null && res.getMapReduceResult() != null) {
      jsonObj.put(PARAM_RESULT_MAP_REDUCE, req.getMapReduceFunction().render(res.getMapReduceResult().getReduceResult()));
    }
  
    return jsonObj;
  }

  private static String formatScore(Integer scoreMeaningfulDigits, float score) {
    if (scoreMeaningfulDigits == null) {
      return String.valueOf(score);
    } else {
      int digits = Math.max(0, scoreMeaningfulDigits);
      return String.format("%." + digits + "f", score);
    }
  }

  private static void addErrors(JSONObject jsonResult, SenseiResult res) throws JSONException {
    JSONArray errorsJson = new FastJSONArray(res.getErrors().size());
    for (SenseiError error: res.getErrors()) {
      errorsJson.put(new FastJSONObject(5).put(PARAM_RESULT_ERROR_MESSAGE, error.getMessage())
                                         .put(PARAM_RESULT_ERROR_TYPE, error.getErrorType().name())
                                         .put(PARAM_RESULT_ERROR_CODE, error.getErrorCode()));
    }
    jsonResult.put(PARAM_RESULT_ERRORS, errorsJson);
    if (res.getErrors().size() > 0) {
      jsonResult.put(PARAM_RESULT_ERROR_CODE, res.getErrors().get(0).getErrorCode());
    } else {
      jsonResult.put(PARAM_RESULT_ERROR_CODE, 0);
    }
  }

  private static SenseiQuery buildSenseiQuery(DataConfiguration params)
  {
    SenseiQuery sq;
    String query = params.getString(PARAM_QUERY, null);

    JSONObject qjson = new FastJSONObject(30);
    if (query != null && query.length() > 0)
    {
      try
      {
        qjson.put("query", query);
      }
      catch (Exception e)
      {
        logger.error(e.getMessage(), e);
      }
    }

    try
    {
      String[] qparams = params.getStringArray(PARAM_QUERY_PARAM);
      for (String qparam : qparams)
      {
        qparam = qparam.trim();
        if (qparam.length() == 0)
          continue;
        String[] parts = qparam.split(":", 2);
        if (parts.length == 2)
        {
          qjson.put(parts[0], parts[1]);
        }
      }
    }
    catch (JSONException jse)
    {
      logger.error(jse.getMessage(), jse);
    }

    sq = new SenseiJSONQuery(qjson);
    return sq;
  }

  @Override
  protected SenseiRequest buildSenseiRequest(DataConfiguration params)
      throws Exception
  {
    return convertSenseiRequest(params);
  }

  public static SenseiRequest convertSenseiRequest(DataConfiguration params)
  {
    SenseiRequest senseiReq = new SenseiRequest();

    convertScalarParams(senseiReq, params);
    convertSenseiQuery(senseiReq, params);
    convertSortParam(senseiReq, params);
    convertSelectParam(senseiReq, params);
    convertFacetParam(senseiReq, params);
    convertInitParams(senseiReq, params);
    convertPartitionParams(senseiReq, params);

    return senseiReq;
  }

  public static void convertSenseiQuery(SenseiRequest senseiReq, DataConfiguration params) {
    senseiReq.setQuery(buildSenseiQuery(params));
  }

  public static void convertScalarParams(SenseiRequest senseiReq, DataConfiguration params) {
    senseiReq.setOffset(params.getInt(PARAM_OFFSET, 0));
    senseiReq.setCount(params.getInt(PARAM_COUNT, 10));
    senseiReq.setShowExplanation(params.getBoolean(PARAM_EXPLAIN, false));
    senseiReq.setTrace(params.getBoolean(PARAM_TRACE, false));
    senseiReq.setSimpleRelevance(params.getBoolean(PARAM_SIMPLE_RELEVANCE, false));
    senseiReq.setFetchStoredFields(params.getBoolean(PARAM_FETCH_STORED, false));
    senseiReq.setFetchStoredValue(params.getBoolean(PARAM_FETCH_STORED_VALUE, false));


    String[] fetchTVs= params.getStringArray(PARAM_FETCH_TERMVECTOR);
    if (fetchTVs!=null && fetchTVs.length>0){
      HashSet<String> tvsToFetch = new HashSet<String>(Arrays.asList(fetchTVs));
      tvsToFetch.remove("");
      if (tvsToFetch.size() > 0)
        senseiReq.setTermVectorsToFetch(tvsToFetch);
    }

    String[] facetsToFetch= params.getStringArray(PARAM_FACETS_TO_FETCH);
    if (facetsToFetch!=null){
      senseiReq.setTermVectorsToFetch( new HashSet<String>(Arrays.asList(facetsToFetch)));
    }

    String groupBy = params.getString(PARAM_GROUP_BY, null);
    if (groupBy != null && groupBy.length() != 0)
      senseiReq.setGroupBy(StringUtils.split(groupBy, ','));
    senseiReq.setMaxPerGroup(params.getInt(PARAM_MAX_PER_GROUP, 0));
    String routeParam = params.getString(PARAM_ROUTE_PARAM);
    if (routeParam != null && routeParam.length() != 0)
      senseiReq.setRouteParam(routeParam);
  }

  public static void convertPartitionParams(SenseiRequest senseiReq, DataConfiguration params)
  {
    if (params.containsKey(PARAM_PARTITIONS)) {
      List<Integer> partitions = params.getList(Integer.class, PARAM_PARTITIONS);
      senseiReq.setPartitions(new HashSet<Integer>(partitions));
    }
  }

  public static void convertInitParams(SenseiRequest senseiReq, DataConfiguration params)
  {
    Map<String, Configuration> facetParamMap = RequestConverter.parseParamConf(params, PARAM_DYNAMIC_INIT);
    Set<Entry<String, Configuration>> facetEntries = facetParamMap.entrySet();

    for (Entry<String, Configuration> facetEntry : facetEntries)
    {
      String facetName = facetEntry.getKey();
      Configuration facetConf = facetEntry.getValue();

      DefaultFacetHandlerInitializerParam facetParams = new DefaultFacetHandlerInitializerParam();

      Iterator paramsIter = facetConf.getKeys();

      while (paramsIter.hasNext())
      {
        String paramName = (String)paramsIter.next();
        Configuration paramConf = (Configuration)facetConf.getProperty(paramName);

        String type = paramConf.getString(PARAM_DYNAMIC_TYPE);
        List<String> vals = paramConf.getList(PARAM_DYNAMIC_VAL);

        try
        {
          String[] attrVals = vals.toArray(new String[0]);

          if (attrVals.length == 0 || attrVals[0].length() == 0)
          {
            logger.warn(String.format("init param has no values: facet: %s, type: %s", facetName, type));
            continue;
          }

          // TODO: smarter dispatching, factory, generics
          if (type.equalsIgnoreCase(PARAM_DYNAMIC_TYPE_BOOL))
          {
            createBooleanInitParam(facetParams, paramName, attrVals);
          }
          else if (type.equalsIgnoreCase(PARAM_DYNAMIC_TYPE_STRING))
          {
            createStringInitParam(facetParams, paramName, attrVals);
          }
          else if (type.equalsIgnoreCase(PARAM_DYNAMIC_TYPE_INT))
          {
            createIntInitParam(facetParams, paramName, attrVals);
          }
          else if (type.equalsIgnoreCase(PARAM_DYNAMIC_TYPE_BYTEARRAY))
          {
            createByteArrayInitParam(facetParams, paramName, paramConf.getString(PARAM_DYNAMIC_VAL));
          }
          else if (type.equalsIgnoreCase(PARAM_DYNAMIC_TYPE_LONG))
          {
            createLongInitParam(facetParams, paramName, attrVals);
          }
          else if (type.equalsIgnoreCase(PARAM_DYNAMIC_TYPE_DOUBLE))
          {
            createDoubleInitParam(facetParams, paramName, attrVals);
          }
          else
          {
            logger.warn(String.format("Unknown init param name: %s, type %s, for facet: %s", paramName, type, facetName));
            continue;
          }

        }
        catch (Exception e)
        {
          logger.warn(String.format("Failed to parse init param name: %s, type %s, for facet: %s", paramName, type, facetName));
        }
      }

      senseiReq.setFacetHandlerInitializerParam(facetName, facetParams);
    }
  }

  private static void createBooleanInitParam(
      DefaultFacetHandlerInitializerParam facetParams,
      String name,
      String[] paramVals)
  {
    boolean[] vals = new boolean[paramVals.length];
    int i = 0;
    for (String paramVal : paramVals ) {
      vals[i++] = Boolean.parseBoolean(paramVal);
    }

    facetParams.putBooleanParam(name, vals);
  }

  private static void createStringInitParam(
      DefaultFacetHandlerInitializerParam facetParams,
      String name,
      String[] paramVals)
  {
    facetParams.putStringParam(name, Arrays.asList(paramVals));
  }

  private static void createIntInitParam(
      DefaultFacetHandlerInitializerParam facetParams,
      String name,
      String[] paramVals)
  {
    int[] vals = new int[paramVals.length];
    int i = 0;
    for (String paramVal : paramVals ) {
      vals[i++] = Integer.parseInt(paramVal);
    }

    facetParams.putIntParam(name, vals);
  }

  private static void createByteArrayInitParam(
      DefaultFacetHandlerInitializerParam facetParams,
      String name,
      String paramVal)
      throws UnsupportedEncodingException
  {
    byte[] val = paramVal.getBytes("UTF-8");
    facetParams.putByteArrayParam(name, val);
  }

  private static void createLongInitParam(
      DefaultFacetHandlerInitializerParam facetParams,
      String name,
      String[] paramVals)
  {
    long[] vals = new long[paramVals.length];
    int i = 0;
    for (String paramVal : paramVals ) {
      vals[i++] = Long.parseLong(paramVal);
    }

    facetParams.putLongParam(name, vals);
  }

  private static void createDoubleInitParam(
      DefaultFacetHandlerInitializerParam facetParams,
      String name,
      String[] paramVals)
  {
    double[] vals = new double[paramVals.length];
    int i = 0;
    for (String paramVal : paramVals ) {
      vals[i++] = Double.parseDouble(paramVal);
    }

    facetParams.putDoubleParam(name, vals);
  }

  public static void convertSortParam(SenseiRequest senseiReq, DataConfiguration params)
  {
    String[] sortStrings = params.getStringArray(PARAM_SORT);

    if (sortStrings != null && sortStrings.length > 0)
    {
      ArrayList<SortField> sortFieldList = new ArrayList<SortField>(sortStrings.length);

      for (String sortString : sortStrings)
      {
        sortString = sortString.trim();
        if (sortString.length() == 0) continue;
        SortField sf;
        String[] parts = sortString.split(":");
        if (parts.length == 2)
        {
          boolean reverse = PARAM_SORT_DESC.equals(parts[1]);
          sf = new SortField(parts[0], SortField.CUSTOM, reverse);
        }
        else if (parts.length == 1)
        {
          if (PARAM_SORT_SCORE.equals(parts[0]))
          {
            sf = SenseiRequest.FIELD_SCORE;
          }
          else if (PARAM_SORT_SCORE_REVERSE.equals(parts[0]))
          {
            sf = SenseiRequest.FIELD_SCORE_REVERSE;
          }
          else if (PARAM_SORT_DOC.equals(parts[0]))
          {
            sf = SenseiRequest.FIELD_DOC;
          }
          else if (PARAM_SORT_DOC_REVERSE.equals(parts[0]))
          {
            sf = SenseiRequest.FIELD_DOC_REVERSE;
          }
          else
          {
            sf = new SortField(parts[0], SortField.CUSTOM, false);
          }
        }
        else
        {
          throw new IllegalArgumentException("invalid sort string: " + sortString);
        }

        if (sf.getType() != SortField.DOC && sf.getType() != SortField.SCORE &&
            (sf.getField() == null || sf.getField().isEmpty()))   // Empty field name.
          continue;

        sortFieldList.add(sf);
      }

      senseiReq.setSort(sortFieldList.toArray(new SortField[sortFieldList.size()]));
    }
  }

  public static void convertFacetParam(SenseiRequest senseiReq, DataConfiguration params)
  {
    Map<String, Configuration> facetParamMap = RequestConverter.parseParamConf(params, PARAM_FACET);
    Set<Entry<String, Configuration>> entries = facetParamMap.entrySet();

    for (Entry<String, Configuration> entry : entries)
    {
      String name = entry.getKey();
      Configuration conf = entry.getValue();
      FacetSpec fspec = new FacetSpec();

      fspec.setExpandSelection(conf.getBoolean(PARAM_FACET_EXPAND, false));
      fspec.setMaxCount(conf.getInt(PARAM_FACET_MAX, 10));
      fspec.setMinHitCount(conf.getInt(PARAM_FACET_MINHIT, 1));

      FacetSpec.FacetSortSpec orderBy;
      String orderString = conf.getString(PARAM_FACET_ORDER, PARAM_FACET_ORDER_HITS);
      if (PARAM_FACET_ORDER_HITS.equals(orderString))
      {
        orderBy = FacetSpec.FacetSortSpec.OrderHitsDesc;
      }
      else if (PARAM_FACET_ORDER_VAL.equals(orderString))
      {
        orderBy = FacetSpec.FacetSortSpec.OrderValueAsc;
      }
      else
      {
        throw new IllegalArgumentException("invalid order string: " + orderString);
      }
      fspec.setOrderBy(orderBy);
      senseiReq.setFacetSpec(name, fspec);
    }
  }

  public static void convertSelectParam(SenseiRequest senseiReq, DataConfiguration params)
  {
    Map<String, Configuration> selectParamMap = RequestConverter.parseParamConf(params, PARAM_SELECT);
    Set<Entry<String, Configuration>> entries = selectParamMap.entrySet();

    for (Entry<String, Configuration> entry : entries)
    {
      String name = entry.getKey();
      Configuration conf = entry.getValue();

      BrowseSelection sel = new BrowseSelection(name);

      String[] vals = conf.getStringArray(PARAM_SELECT_VAL);
      for (String val : vals)
      {
        if (val.trim().length() > 0)
        {
          sel.addValue(val);
        }
      }

      vals = conf.getStringArray(PARAM_SELECT_NOT);
      for (String val : vals)
      {
        if (val.trim().length() > 0)
        {
          sel.addNotValue(val);
        }
      }

      String op = conf.getString(PARAM_SELECT_OP, PARAM_SELECT_OP_OR);

      ValueOperation valOp;
      if (PARAM_SELECT_OP_OR.equals(op))
      {
        valOp = ValueOperation.ValueOperationOr;
      }
      else if (PARAM_SELECT_OP_AND.equals(op))
      {
        valOp = ValueOperation.ValueOperationAnd;
      }
      else
      {
        throw new IllegalArgumentException("invalid selection operation: " + op);
      }
      sel.setSelectionOperation(valOp);

      String[] selectPropStrings = conf.getStringArray(PARAM_SELECT_PROP);
      if (selectPropStrings != null && selectPropStrings.length > 0)
      {
        Map<String, String> prop = new HashMap<String, String>();
        for (String selProp : selectPropStrings)
        {
          if (selProp.trim().length() == 0) continue;

          String[] parts = selProp.split(":");
          if (parts.length == 2)
          {
            prop.put(parts[0], parts[1]);
          }
          else
          {
            throw new IllegalArgumentException("invalid prop string: " + selProp);
          }
        }
        sel.setSelectionProperties(prop);
      }

      senseiReq.addSelection(sel);
    }
  }

  @Override
  protected String buildResultString(HttpServletRequest httpReq, SenseiSystemInfo info) throws Exception {
    JSONObject jsonObj = new FastJSONObject(8);
    jsonObj.put(PARAM_SYSINFO_NUMDOCS, info.getNumDocs());
    jsonObj.put(PARAM_SYSINFO_LASTMODIFIED, info.getLastModified());
    jsonObj.put(PARAM_SYSINFO_VERSION, info.getVersion());

    if (info.getSchema() != null && info.getSchema().length() != 0)
    {
      jsonObj.put(PARAM_SYSINFO_SCHEMA, new FastJSONObject(info.getSchema()));
    }

    Set<SenseiSystemInfo.SenseiFacetInfo> facets = info.getFacetInfos();
    JSONArray jsonArray = new FastJSONArray(facets == null ? 0 : facets.size());
    if (facets != null) {
        for (SenseiSystemInfo.SenseiFacetInfo facet : facets) {
          JSONObject facetObj = new FastJSONObject(6);
          facetObj.put(PARAM_SYSINFO_FACETS_NAME, facet.getName());
          facetObj.put(PARAM_SYSINFO_FACETS_RUNTIME, facet.isRunTime());
          facetObj.put(PARAM_SYSINFO_FACETS_PROPS, facet.getProps());
          jsonArray.put(facetObj);
        }
    }
    jsonObj.put(PARAM_SYSINFO_FACETS, jsonArray);

    List<SenseiSystemInfo.SenseiNodeInfo> clusterInfo = info.getClusterInfo();
    jsonArray = new FastJSONArray(clusterInfo == null ? 0 : clusterInfo.size());
    if (clusterInfo != null)
    {
      for (SenseiSystemInfo.SenseiNodeInfo nodeInfo : clusterInfo)
      {
        JSONObject nodeObj = new FastJSONObject(7);
        nodeObj.put(PARAM_SYSINFO_CLUSTERINFO_ID, nodeInfo.getId());
        nodeObj.put(PARAM_SYSINFO_CLUSTERINFO_PARTITIONS, new FastJSONArray(Arrays.asList(nodeInfo.getPartitions())));
        nodeObj.put(PARAM_SYSINFO_CLUSTERINFO_NODELINK, nodeInfo.getNodeLink());
        nodeObj.put(PARAM_SYSINFO_CLUSTERINFO_ADMINLINK, nodeInfo.getAdminLink());
        jsonArray.put(nodeObj);
      }
    }
    jsonObj.put(PARAM_SYSINFO_CLUSTERINFO, jsonArray);

    return supportJsonp(httpReq, jsonObj.toString());
  }
}
TOP

Related Classes of com.senseidb.servlet.DefaultSenseiJSONServlet

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.