package org.nlpcn.es4sql.domain.hints;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.yaml.YamlXContentParser;
import org.nlpcn.es4sql.exception.SqlParseException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by Eliran on 5/9/2015.
*/
public class HintFactory {
public static Hint getHintFromString(String hintAsString) throws SqlParseException {
if(hintAsString.startsWith("! USE_NESTED_LOOPS") || hintAsString.startsWith("! USE_NL")){
return new Hint(HintType.USE_NESTED_LOOPS,null);
}
if(hintAsString.startsWith("! SHARD_SIZE")){
String[] numbers = getParamsFromHint(hintAsString, "! SHARD_SIZE");
//todo: check if numbers etc..
List<Object> params = new ArrayList<>();
for (String number : numbers){
if(number.equals("null") || number.equals("infinity")){
params.add(null);
}
else {
params.add(Integer.parseInt(number));
}
}
return new Hint(HintType.SHARD_SIZE,params.toArray());
}
if(hintAsString.equals("! HASH_WITH_TERMS_FILTER"))
return new Hint(HintType.HASH_WITH_TERMS_FILTER,null);
if(hintAsString.startsWith("! JOIN_TABLES_LIMIT")){
String[] numbers = getParamsFromHint(hintAsString, "! JOIN_TABLES_LIMIT");
//todo: check if numbers etc..
List<Object> params = new ArrayList<>();
for (String number : numbers){
if(number.equals("null") || number.equals("infinity")){
params.add(null);
}
else {
params.add(Integer.parseInt(number));
}
}
return new Hint(HintType.JOIN_LIMIT,params.toArray());
}
if(hintAsString.startsWith("! NL_MULTISEARCH_SIZE")) {
String[] number = getParamsFromHint(hintAsString,"! NL_MULTISEARCH_SIZE");
//todo: check if numbers etc..
int multiSearchSize = Integer.parseInt(number[0]);
return new Hint(HintType.NL_MULTISEARCH_SIZE,new Object[]{multiSearchSize});
}
if(hintAsString.startsWith("! USE_SCROLL")){
String[] scrollParams = getParamsFromHint(hintAsString,"! USE_SCROLL");
int docsPerShardFetch = 50;
int timeout = 60000;
if(scrollParams != null && scrollParams.length ==2) {
docsPerShardFetch = Integer.parseInt(scrollParams[0]);
timeout = Integer.parseInt(scrollParams[1]);
}
return new Hint(HintType.USE_SCROLL, new Object[]{docsPerShardFetch,timeout});
}
if(hintAsString.startsWith("! IGNORE_UNAVAILABLE")){
return new Hint(HintType.IGNORE_UNAVAILABLE,null);
}
if(hintAsString.startsWith("! DOCS_WITH_AGGREGATION")) {
Integer[] params = parseParamsAsInts(hintAsString,"! DOCS_WITH_AGGREGATION");
return new Hint(HintType.DOCS_WITH_AGGREGATION, params);
}
if(hintAsString.startsWith("! ROUTINGS")) {
String[] routings = getParamsFromHint(hintAsString,"! ROUTINGS");
return new Hint(HintType.ROUTINGS,routings);
}
if(hintAsString.startsWith("! HIGHLIGHT")) {
String[] heighlights = getParamsFromHint(hintAsString,"! HIGHLIGHT");
ArrayList hintParams = new ArrayList();
hintParams.add(heighlights[0]);
if(heighlights.length > 1 ){
StringBuilder builder = new StringBuilder();
for(int i=1;i<heighlights.length;i++){
if(i!=1){
builder.append("\n");
}
builder.append(heighlights[i]);
}
String heighlightParam = builder.toString();
YAMLFactory yamlFactory = new YAMLFactory();
YAMLParser yamlParser = null;
try {
yamlParser = yamlFactory.createParser(heighlightParam.toCharArray());
YamlXContentParser yamlXContentParser = new YamlXContentParser(NamedXContentRegistry.EMPTY, yamlParser);
Map<String, Object> map = yamlXContentParser.map();
hintParams.add(map);
} catch (IOException e) {
throw new SqlParseException("could not parse heighlight hint: " + e.getMessage());
}
}
return new Hint(HintType.HIGHLIGHT,hintParams.toArray());
}
if(hintAsString.startsWith("! MINUS_SCROLL_FETCH_AND_RESULT_LIMITS")){
Integer[] params = parseParamsAsInts(hintAsString,"! MINUS_SCROLL_FETCH_AND_RESULT_LIMITS");
if( params.length>3){
throw new SqlParseException("MINUS_FETCH_AND_RESULT_LIMITS should have 3 int params (maxFromFirst,maxFromSecond,hitsPerScrollShard)");
}
Integer[] paramsWithDefaults = new Integer[3];
int defaultMaxFetchFromTable = 100000;
int defaultFetchOnScroll = 1000;
paramsWithDefaults[0] = defaultMaxFetchFromTable;
paramsWithDefaults[1] = defaultMaxFetchFromTable;
paramsWithDefaults[2] = defaultFetchOnScroll;
for(int i=0;i<params.length;i++){
paramsWithDefaults[i]=params[i];
}
return new Hint(HintType.MINUS_FETCH_AND_RESULT_LIMITS, paramsWithDefaults);
}
if(hintAsString.startsWith("! MINUS_USE_TERMS_OPTIMIZATION")){
String[] param = getParamsFromHint(hintAsString,"! MINUS_USE_TERMS_OPTIMIZATION");
boolean shouldLowerStringOnTerms = false;
if(param!=null ){
if(param.length!=1) {
throw new SqlParseException("MINUS_USE_TERMS_OPTIMIZATION should have none or one boolean param: false/true ");
}
try {
shouldLowerStringOnTerms = Boolean.parseBoolean(param[0].toLowerCase());
}
catch (Exception e){
throw new SqlParseException("MINUS_USE_TERMS_OPTIMIZATION should have none or one boolean param: false/true , got:" + param[0]);
}
}
return new Hint(HintType.MINUS_USE_TERMS_OPTIMIZATION, new Object[]{shouldLowerStringOnTerms});
}
return null;
}
private static String[] getParamsFromHint(String hint, String prefix) {
if(!hint.contains("(")) return null;
String onlyParams = hint.replace(prefix, "").replaceAll("\\s*\\(\\s*","").replaceAll("\\s*\\,\\s*", ",").replaceAll("\\s*\\)\\s*", "");
return onlyParams.split(",");
}
private static Integer[] parseParamsAsInts(String hintAsString,String startWith) {
String[] number = getParamsFromHint(hintAsString,startWith);
if(number == null){
return new Integer[0];
}
//todo: check if numbers etc..
Integer[] params = new Integer[number.length];
for (int i = 0; i < params.length; i++) {
params[i] = Integer.parseInt(number[i]);
}
return params;
}
}