/** * 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()); } }