/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.linkedin.pinot.pql.parsers.utils; import com.linkedin.pinot.common.Utils; import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import com.linkedin.pinot.pql.parsers.utils.JSONUtil.FastJSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PQLParserUtils { private static final Logger LOGGER = LoggerFactory.getLogger(PQLParserUtils.class); public static void decorateWithMapReduce(JSONObject jsonObj, java.util.List<Pair<String, String>> aggreagationFunctions, JSONObject groupBy, String functionName, JSONObject parameters) { try { if (aggreagationFunctions == null) { aggreagationFunctions = new ArrayList<Pair<String, String>>(); } if (aggreagationFunctions.size() > 0) { JSONObject meta = jsonObj.optJSONObject("meta"); if (meta != null) { JSONArray selectList = meta.optJSONArray("select_list"); if (selectList == null || selectList.length() == 0) { meta.put("select_list", new JSONUtil.FastJSONArray().put("*")); } } } JSONArray array = new JSONUtil.FastJSONArray(); if (groupBy == null) { for (Pair<String, String> pair : aggreagationFunctions) { JSONObject props = new JSONUtil.FastJSONObject(); props.put("column", pair.getSecond()); props.put("mapReduce", pair.getFirst()); array.put(props); } } else { JSONArray columns = groupBy.optJSONArray("columns"); if (aggreagationFunctions.size() > 0) { groupBy.put("columns", (JSONArray) null); } int countSum = 0; int top = groupBy.optInt("top"); for (Pair<String, String> pair : aggreagationFunctions) { //we need to skip the optimization for sum group by, as it breaks restli functionality in Pinot /*if (columns.length() == 1 && "sum".equalsIgnoreCase(pair.getFirst()) && countSum == 0) { countSum++; JSONObject facetSpec = new FastJSONObject().put("expand", false) .put("minhit", 0) .put("max", top).put("properties", new FastJSONObject().put("dimension", columns.get(0)).put("metric", pair.getSecond())); if (jsonObj.opt("facets") == null) { jsonObj.put("facets", new FastJSONObject()); } jsonObj.getJSONObject("facets").put(SenseiFacetHandlerBuilder.SUM_GROUP_BY_FACET_NAME, facetSpec); } else*/if (columns.length() == 1 && "count".equalsIgnoreCase(pair.getFirst())) { JSONObject facetSpec = new FastJSONObject().put("expand", false).put("minhit", 0).put("max", top); if (jsonObj.opt("facets") == null) { jsonObj.put("facets", new FastJSONObject()); } jsonObj.getJSONObject("facets").put(columns.getString(0), facetSpec); } else { JSONObject props = new JSONUtil.FastJSONObject(); props.put("function", pair.getFirst()); props.put("metric", pair.getSecond()); props.put("columns", columns); props.put("mapReduce", "sensei.groupBy"); props.put("top", top); array.put(props); } } } if (functionName != null) { if (parameters == null) { parameters = new JSONUtil.FastJSONObject(); } parameters.put("mapReduce", functionName); array.put(parameters); } JSONObject mapReduce = new JSONUtil.FastJSONObject(); if (array.length() == 0) { return; } if (array.length() == 1) { JSONObject props = array.getJSONObject(0); mapReduce.put("function", props.get("mapReduce")); mapReduce.put("parameters", props); } else { mapReduce.put("function", "sensei.composite"); JSONObject props = new JSONUtil.FastJSONObject(); props.put("array", array); mapReduce.put("parameters", props); } jsonObj.put("mapReduce", mapReduce); // we need to remove group by since it's in Map reduce //jsonObj.remove("groupBy"); } catch (JSONException e) { LOGGER.error("Caught exception", e); Utils.rethrowException(e); throw new AssertionError("Should not reach this"); } } /** * Converts MySQL LIKE expression to java Regex * @param expr * @return */ public static String convertLikeExpressionToJavaRegex(String expr) { //escape all special characters used in java regex expr = expr.replaceAll(".", "\\."); expr = expr.replaceAll("[", "\\["); expr = expr.replaceAll("]", "\\]"); expr = expr.replaceAll("(", "\\("); expr = expr.replaceAll(")", "\\)"); //replace non escaped LIKE characters (% and _) with equivalent java regex expr = expr.replaceAll("[^\\]_", "."); expr = expr.replaceAll("[^\\%]", ".*?"); //replace escaped % and _ characters with % and _ since java regex dont have any special meaning for that expr = expr.replaceAll("\\%", "%"); expr = expr.replaceAll("\\_", "_"); return expr; } }