/*
* Copyright 2013 Websquared, Inc.
*
* 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 org.fastcatsearch.query;
import org.fastcatsearch.error.ServerErrorCode;
import org.fastcatsearch.error.SearchError;
import org.fastcatsearch.ir.group.GroupFunction;
import org.fastcatsearch.ir.group.GroupFunctionType;
import org.fastcatsearch.ir.query.*;
import org.fastcatsearch.ir.query.Term.Option;
import org.fastcatsearch.ir.search.StoredProcedure;
import org.fastcatsearch.ir.search.clause.Clause;
import org.fastcatsearch.util.DynamicClassLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
/**
*
*
* @author sangwook.song
*
*/
public class QueryParser {
private static Logger logger = LoggerFactory.getLogger(QueryParser.class);
private static final String PLUGIN_PACKAGE_PATH = "org.fastcatsearch.ir.group.function";
private static final String PLUGIN_CLASSNAME_SUFFIX = "GroupFunction";
private static QueryParser instance = new QueryParser();
private static final String SECTION_SEPARATOR = "(?<!\\\\)&";
private static final String VALUE_SEPARATOR = "(?<!\\\\)=";
private static final String COMMA_SEPARATOR = "(?<!\\\\),";
private static final String COLON_SEPARATOR = "(?<!\\\\):";
private static final String SEMICOLON_SEPARATOR = "(?<!\\\\);";
private static final String RANGE_SEPARATOR = "(?<!\\\\)~";
private QueryParser() {
}
public static QueryParser getInstance() {
return instance;
}
// 검색 term 에서 사용
private String removeEscape(String str) {
return str.replaceAll("\\\\:", ":").replaceAll("\\\\&", "&").replaceAll("\\\\=", "=").replaceAll("\\\\,", ",");
}
// 필터 값에서 사용.
// 필터는 여러 값으로 필터링이 가능해야 하므로 ; 구분자를 사용한다.
// 그리고 범위지정에 ~를 사용한다.
private void removeEscape(String[] strList) {
for (int i = 0; i < strList.length; i++)
strList[i] = strList[i].replaceAll("\\\\:", ":").replaceAll("\\\\&", "&").replaceAll("\\\\=", "=").replaceAll("\\\\,", ",")
.replaceAll("\\\\;", ";").replaceAll("\\\\~", "~");
}
public Query parseQuery(QueryMap queryMap) {
Query query = new Query();
Iterator<Entry<String, String>> iterator = queryMap.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue().trim();
if (value != null) {
fillQuery(query, key, value);
}
}
return query;
}
public Query.EL detectElement(String name) {
try {
//EL enum이 소문자이므로 소문자로 바꾼다.
return Query.EL.valueOf(name.toLowerCase());
} catch (IllegalArgumentException e) {
return null;
}
}
private void fillQuery(Query query, String key, String value) {
Query.EL el = detectElement(key);
if (el == null || value.length() == 0) {
return;
}
logger.debug("fill {} >> {}", key, value);
if (Query.EL.cn == el) {
Metadata m = query.getMeta();
m.setCollectionId(value);
} else if (Query.EL.ht == el) {
Metadata m1 = query.getMeta();
String tags[] = value.split(COLON_SEPARATOR);
if(tags.length != 2) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Highlighting tag must contains start and end tag with colon. : " + value);
}
removeEscape(tags);
m1.setTags(tags);
} else if (Query.EL.sn == el) {
Metadata m2 = query.getMeta();
int sn = Integer.parseInt(value);
if (sn < 1) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Start number has to be greater than 0.");
}
m2.setStart(sn);
} else if (Query.EL.ln == el) {
Metadata m3 = query.getMeta();
int len = Integer.parseInt(value);
if (len < 1)
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Length has to be greater than 0.");
m3.setRows(len);
} else if (Query.EL.so == el) {
Metadata m4 = query.getMeta();
m4.setSearchOptions(value);
} else if (Query.EL.ud == el) {
Metadata m5 = query.getMeta();
String[] list = value.split(COMMA_SEPARATOR);
HashMap<String, String> map = new HashMap<String, String>();
for (int k = 0; k < list.length; k++) {
String[] keyValue = list[k].split(COLON_SEPARATOR);
// key:value 매핑.
if (keyValue.length == 2) {
removeEscape(keyValue);
map.put(keyValue[0].toUpperCase(), keyValue[1]);
}
}
m5.setUserData(map);
} else if (Query.EL.fl == el) {
String[] list = value.split(COMMA_SEPARATOR);
ViewContainer views = new ViewContainer(list.length);
for (int k = 0; k < list.length; k++) {
String[] str = list[k].split(COLON_SEPARATOR);
if (str.length > 2) {
views.add(new View(str[0].trim(), Integer.parseInt(str[1].trim()), Integer.parseInt(str[2].trim())));
} else if (str.length > 1) {
views.add(new View(str[0].trim(), Integer.parseInt(str[1].trim())));
} else {
views.add(new View(list[k]));
}
}
query.setViews(views);
} else if (Query.EL.se == el) {
if (value.length() > 0) {
Object obj = makeClause(value);
Clause clause = null;
if(obj instanceof Term){
clause = new Clause((Term) obj);
}else{
clause = (Clause) makeClause(value);
}
query.setClause(clause);
}
} else if (Query.EL.ft == el) {
Filters f = makeFilters(value);
query.setFilters(f);
} else if (Query.EL.gr == el) {
String[] list = value.split(COMMA_SEPARATOR);
Groups g = new Groups();
for (int k = 0; k < list.length; k++) {
String[] items = list[k].split(COLON_SEPARATOR);
if (items.length < 2) {
// 정보부족 에러.
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Grouping syntax is invalid : " + list[k]);
}
String field = items[0].trim();
// String shortFunctionName = items[1];
int limit = -1;
int sortOrder = 0;
// function은 ; 구분으로 파라미터 나눈다.
// 기능이름;파라미터1;파라미터2 등둥..
String[] functionList = items[1].split(SEMICOLON_SEPARATOR);
if (items.length > 2) {
if (items.length > 3) {
// 마지막은 limit이다.
limit = Integer.parseInt(items[3].trim());
}
// items[2]는 정렬옵션
sortOrder = getGroupSortOrder(items[2].trim());
}
GroupFunction[] groupFunctions = new GroupFunction[functionList.length];
for (int j = 0; j < functionList.length; j++) {
String functionExpr = functionList[j];
String functionName = null;
String param = null;
if (functionExpr.contains("(")) {
String[] funcTmp = functionExpr.split("\\(");
functionName = funcTmp[0];
param = funcTmp[1].substring(0, funcTmp[1].length() - 1);
} else {
functionName = functionExpr;
}
if(functionName != null) {
functionName = functionName.toUpperCase();
}
try{
GroupFunctionType groupFunctionType = GroupFunctionType.valueOf(functionName);
groupFunctions[j] = new GroupFunction(groupFunctionType, sortOrder, param);
} catch (Exception e) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Unknown group function '"+ functionName +"'.");
}
}
g.add(new Group(field, groupFunctions, sortOrder, limit));
}
query.setGroups(g);
} else if (Query.EL.gf == el) {
Filters f = makeFilters(value);
query.setGroupFilters(f);
} else if (Query.EL.ra == el) {
Sorts s = new Sorts();
String[] list = value.split(COMMA_SEPARATOR);
for (int k = 0; k < list.length; k++) {
String[] str = list[k].split(COLON_SEPARATOR);
if (str.length > 1) {
boolean isAsc, isShuffle;
// asc일 시 isAsc true
if (str[1].equalsIgnoreCase("asc") || str[1].equalsIgnoreCase("asc_shuffle")) {
isAsc = true;
} else {
isAsc = false;
}
//_shuffle 로 endwith 면, isShuffle 을 true
if (str[1].endsWith("_shuffle") || str[1].endsWith("_SHUFFLE")) {
isShuffle = true;
} else {
isShuffle = false;
}
s.add(new Sort(str[0], isAsc, isShuffle));
} else {
s.add(new Sort(list[k]));
}
}
query.setSorts(s);
} else if (Query.EL.qm == el) {
Metadata m = query.getMeta();
QueryModifier queryModifier = (QueryModifier) DynamicClassLoader.loadObject(value);
if(queryModifier == null) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Cannot find query modifier '"+ value +"'.");
}
m.setQueryModifier(queryModifier);
} else if (Query.EL.rm == el) {
Metadata m = query.getMeta();
ResultModifier resultModifier = (ResultModifier) DynamicClassLoader.loadObject(value);
if(resultModifier == null) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Cannot find result modifier '"+ value +"'.");
}
m.setResultModifier(resultModifier);
} else if (Query.EL.sp == el) {
Metadata m = query.getMeta();
StoredProcedure sp = (StoredProcedure) DynamicClassLoader.loadObject(value);
if(sp == null) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Cannot find stored procedure '"+ value +"'.");
}
m.setStoredProcedure(sp);
} else if (Query.EL.bd == el) {
String[] list = value.split(SEMICOLON_SEPARATOR);
String[] list1 = list[0].split(COLON_SEPARATOR);
Bundle b = new Bundle(list1[0].trim());
if(list1.length > 1) {
int bundleRows = 5; //default 5개.
try{
bundleRows = Integer.parseInt(list1[1].trim());
}catch(NumberFormatException e) {
//ignore
}
b.setRows(bundleRows);
}
if(list1.length > 2) {
int option = Bundle.OPT_PARENT_INCLUDE; //대표포함.
try{
option = Integer.parseInt(list1[2].trim());
}catch(NumberFormatException e) {
//ignore
}
b.setOption(option);
} else {
b.setOption(Bundle.OPT_PARENT_INCLUDE);
}
if(list.length > 1) {
Sorts s = new Sorts();
String[] sortList = list[1].split(COMMA_SEPARATOR);
for (int k = 0; k < sortList.length; k++) {
String[] str = sortList[k].split(COLON_SEPARATOR);
if (str.length > 1) {
boolean isAsc = str[1].equalsIgnoreCase("asc");
s.add(new Sort(str[0], isAsc));
} else {
s.add(new Sort(sortList[k]));
}
}
b.setSorts(s);
}
query.setBundle(b);
}
}
/**
* @Deprecated 대신 parseQuery(QueryMap queryMap) 를 사용하기 바람.
* */
public Query parseQuery(String queryString) {
String[] groups = queryString.split(SECTION_SEPARATOR);
Query query = new Query();
query.setMeta(new Metadata());
for (int i = 0; i < groups.length; i++) {
String[] tmp = groups[i].split(VALUE_SEPARATOR);
if (tmp.length < 2) {
continue;
}
String key = tmp[0];
String value = tmp[1];
if (value == null || value.length() == 0) {
continue;
}
fillQuery(query, key, value);
}
logger.debug("query = {}", query);
return query;
}
private static String convertToClassName(String groupFunctionName) {
String tempClassName = null;
String packageName = null;
String className = "";
if (groupFunctionName.contains(".")) {
int idx = groupFunctionName.lastIndexOf(".");
packageName = groupFunctionName.substring(0, idx);
tempClassName = groupFunctionName.substring(idx + 1);
} else {
tempClassName = groupFunctionName;
}
if (tempClassName.contains("_")) {
String[] parts2 = tempClassName.split("_");
for (int i = 0; i < parts2.length; i++) {
className += capitalize(parts2[i]);
}
} else {
className = capitalize(groupFunctionName);
}
if (packageName != null) {
return PLUGIN_PACKAGE_PATH + "." + packageName + "." + className + PLUGIN_CLASSNAME_SUFFIX;
} else {
return PLUGIN_PACKAGE_PATH + "." + className + PLUGIN_CLASSNAME_SUFFIX;
}
}
private static String capitalize(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'a' && firstChar <= 'z') {
return ((char) (firstChar - 32)) + str.substring(1);
} else {
return str;
}
}
private int getGroupSortOrder(String string) {
if (string.equalsIgnoreCase("KEY_ASC")) {
return Group.SORT_KEY_ASC;
} else if (string.equalsIgnoreCase("KEY_DESC")) {
return Group.SORT_KEY_DESC;
} else if (string.equalsIgnoreCase("COUNT_ASC") || string.equalsIgnoreCase("VALUE_ASC")) {
return Group.SORT_VALUE_ASC;
} else if (string.equalsIgnoreCase("COUNT_DESC") || string.equalsIgnoreCase("VALUE_DESC")) {
return Group.SORT_VALUE_DESC;
}
return 0;
}
//
// TODO 괄호없이 A or B and C 형태도 가능토록, escapse 문자 '\' 적용필요.
//
protected Object makeClause(String value) {
logger.trace("makeClause = {}", value);
if (value.charAt(0) == '{') {
int pos = findMatchBrace(value, 1);
if (pos < 0) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Close brace not found : " + value);
}
// logger.debug("pos={}, value={}",pos, value);
Object operand1 = makeClause(value.substring(1, pos));
if (value.regionMatches(true, pos + 1, Clause.Operator.OR.name(), 0, 2)) {
int end = findMatchBrace(value, pos + 4);// value.indexOf('}', pos + 4);
Object operand2 = makeClause(value.substring(pos + 4, end));
if(operand2 instanceof Clause) {
Clause innerClause = (Clause)operand2;
if(innerClause.operator() == Clause.Operator.NOT && innerClause.operand1() == null) {
logger.info("OR-NOT Clause detected : [{}]OR[NOT[{}]]", operand1, innerClause.operand2());
}
}
return new Clause(operand1, Clause.Operator.OR, operand2);
} else if (value.regionMatches(true, pos + 1, Clause.Operator.AND.name(), 0, 3)) {
int end = findMatchBrace(value, pos + 5);// value.indexOf('}', pos + 5);
Object operand2 = makeClause(value.substring(pos + 5, end));
if(operand2 instanceof Clause) {
Clause innerClause = (Clause)operand2;
if(innerClause.operator() == Clause.Operator.NOT && innerClause.operand1() == null) {
return new Clause(operand1, Clause.Operator.NOT, innerClause.operand2());
}
}
return new Clause(operand1, Clause.Operator.AND, operand2);
} else if (value.regionMatches(true, pos + 1, Clause.Operator.NOT.name(), 0, 3)) {
int end = findMatchBrace(value, pos + 5);// value.indexOf('}', pos + 5);
Object operand2 = makeClause(value.substring(pos + 5, end));
return new Clause(operand1, Clause.Operator.NOT, operand2);
} else if (value.regionMatches(true, pos + 1, Clause.Operator.BOOST.name(), 0, 5)) {
int end = findMatchBrace(value, pos + 7);
Object operand2 = makeClause(value.substring(pos + 7, end));
if(operand2 instanceof Clause) {
Clause innerClause = (Clause)operand2;
if(innerClause.operator() == Clause.Operator.NOT && innerClause.operand1() == null) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "BOOST-uni NOT is not supported : " + value);
}
}
return new Clause(operand1, Clause.Operator.BOOST, operand2);
} else if (value.regionMatches(true, pos + 1, Clause.Operator.LOR.name(), 0, 3)) {
int end = findMatchBrace(value, pos + 5);
Object operand2 = makeClause(value.substring(pos + 5, end));
if(operand2 instanceof Clause) {
Clause innerClause = (Clause)operand2;
if(innerClause.operator() == Clause.Operator.NOT && innerClause.operand1() == null) {
logger.info("OR-NOT Clause detected : [{}]OR[NOT[{}]]", operand1, innerClause.operand2());
}
}
return new Clause(operand1, Clause.Operator.LOR, operand2);
} else {
// operator가 없거나 잘못되었으면 뒤는 무시하고 operand1 이 term으로 간주된다.
if (operand1 instanceof Term)
return new Clause(operand1);
else
return operand1;
}
} else {
/*
* Unary NOT을 지원하기위함. 예) NOT{title,body:AND(방송):100:32}
*/
if (value.startsWith(Clause.Operator.NOT.name()+"{")) {
int end = findMatchBrace(value, 4);
Object operand2 = makeClause(value.substring(4, end));
return new Clause(null, Clause.Operator.NOT, operand2);
} else {
Term term = makeTerm(value);
return term;
}
}
}
private int findMatchBrace(String value, int m) {
int depth = 0;
for (; m < value.length(); m++) {
// logger.debug(m+"="+value.charAt(m));
if (value.charAt(m) == '{' && ( m == 0 || value.charAt(m - 1) != '\\')) {
depth++;
// logger.debug("depth="+depth);
} else if (value.charAt(m) == '}' && ( m == 0 || value.charAt(m - 1) != '\\')) {
// logger.debug("depth="+depth);
if (depth == 0)
return m;
depth--;
// logger.debug("depth="+depth);
}
}
return -1;
}
private Term makeTerm(String value) {
logger.debug("Term => {}", value);
String[] list = value.split(COLON_SEPARATOR);
int[] proximity = new int[1];
if (list.length == 1) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Search field must contain field id and keyword : " + value);
} else if (list.length == 2) {
// field:term
String[] fieldList = list[0].replaceAll(" ", "").split(COMMA_SEPARATOR);
String[] term = new String[1];
Term.Type type = getType(list[1], term, proximity);
return new Term(fieldList, removeEscape(term[0]), type).withProximity(proximity[0]);
} else if (list.length == 3) {
// field:term:score
String[] fieldList = list[0].replaceAll(" ", "").split(COMMA_SEPARATOR);
String[] term = new String[1];
Term.Type type = getType(list[1], term, proximity);
return new Term(fieldList, removeEscape(term[0]), Integer.parseInt(list[2]), type).withProximity(proximity[0]);
} else if (list.length == 4) {
// field:term:score:option
String[] fieldList = list[0].replaceAll(" ", "").split(COMMA_SEPARATOR);
String[] term = new String[1];
Term.Type type = getType(list[1], term, proximity);
return new Term(fieldList, removeEscape(term[0]), Integer.parseInt(list[2]), type, new Option(Integer.parseInt(list[3]))).withProximity(proximity[0]);
} else {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Search field has too many options. Check search keyword escape colon symbol. : " + value);
}
}
private Term.Type getType(String str, String[] term, int[] proximity) {
if (str.startsWith("ALL(")) {
if(str.endsWith(")")) {
term[0] = str.substring(4, str.length() - 1);
} else {
int p = str.lastIndexOf(")");
if (str.length() > p + 2) {
char ch = str.charAt(p + 1);
if (ch == '~') {
String proximityStr = str.substring(p + 2);
proximityStr = proximityStr.trim();
if(proximity.length == 0){
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Proximity cannot be empty.");
}
try {
proximity[0] = Integer.parseInt(proximityStr);
} catch (NumberFormatException e) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Proximity is not an integer number : " + proximityStr);
}
}
term[0] = str.substring(4, p);
}
}
return Term.Type.ALL;
} else if (str.startsWith("ANY(")) {
// term[0] = str.substring(4, str.length() - 1);
if(str.endsWith(")")) {
term[0] = str.substring(4, str.length() - 1);
} else {
int p = str.lastIndexOf(")");
if (str.length() > p + 2) {
char ch = str.charAt(p + 1);
if (ch == '~') {
String proximityStr = str.substring(p + 2);
proximityStr = proximityStr.trim();
if(proximity.length == 0){
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Proximity cannot be empty.");
}
try {
proximity[0] = Integer.parseInt(proximityStr);
} catch (NumberFormatException e) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Proximity is not an integer number : " + proximityStr);
}
}
term[0] = str.substring(4, p);
}
}
return Term.Type.ANY;
} else if (str.startsWith("EXT(")) {
term[0] = str.substring(4, str.length() - 1);
logger.debug("str = " + str);
return Term.Type.EXT;
} else if (str.startsWith("PHRASE(")) {
term[0] = str.substring(7, str.length() - 1);
logger.debug("str = " + str);
return Term.Type.PHRASE;
} else if (str.startsWith("BOOL(")) {
term[0] = str.substring(5, str.length() - 1);
logger.debug("str = " + str);
return Term.Type.BOOL;
}
// 통째로 반환. default = AND
term[0] = str;
return Term.Type.ALL;
}
private Filters makeFilters(String value) {
//
// Syntax : [FieldId;..] : [Filter Function] [(param;..)] : [Value;..] : [Boosting Score]
//
String[] list = value.split(COMMA_SEPARATOR);
Filters f = new Filters();
for (int k = 0; k < list.length; k++) {
String[] str = list[k].split(COLON_SEPARATOR);
if (str.length <= 1) {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Filter syntax is invalid : " + value);
}
// else if (str.length <= 2) {
// logger.error("Filter param string is empty. >> {}", value);
// return f;
// }
String field = str[0];
String function = str[1];
String[] fieldList = field.split(SEMICOLON_SEPARATOR);
//method 함수에 딸린 파라미터. 괄호안에 ; 구분으로 들어있음.
String[] functionParamList = null;
if(function.contains("(") && function.contains(")")) {
String tmp = function;
int spos = tmp.indexOf("(");
int epos = tmp.lastIndexOf(")");
function = tmp.substring(0, spos);
String paramStr = tmp.substring(spos + 1, epos);
functionParamList = paramStr.split(SEMICOLON_SEPARATOR);
for(int i = 0; i < functionParamList.length; i++) {
functionParamList[i] = functionParamList[i].trim();
}
}
String[] parameterList = null;
if(str.length > 2){
parameterList = str[2].split(SEMICOLON_SEPARATOR);
removeEscape(parameterList);
}
int boostScore = 0;
if(str.length > 3){
boostScore = Integer.parseInt(str[3]);
}
if (function.equalsIgnoreCase("MATCH")) {
f.add(new Filter(field, Filter.MATCH, functionParamList, parameterList));
} else if (function.equalsIgnoreCase("SECTION")) {
String[] patList = new String[parameterList.length];
String[] endPatList = new String[parameterList.length];
for (int i = 0; i < parameterList.length; i++) {
String[] range = parameterList[i].split(RANGE_SEPARATOR);
patList[i] = range[0];
if (range.length >= 2) {
endPatList[i] = range[1];
logger.debug("[" + patList[i] + "~" + endPatList[i] + "]");
} else {
endPatList[i] = "";
logger.debug("[" + patList[i] + "~]");
}
}
f.add(new Filter(field, Filter.SECTION, functionParamList, patList, endPatList));
} else if (function.equalsIgnoreCase("PREFIX")) {
f.add(new Filter(field, Filter.PREFIX, functionParamList, parameterList));
} else if (function.equalsIgnoreCase("SUFFIX")) {
f.add(new Filter(field, Filter.SUFFIX, functionParamList, parameterList));
} else if (function.equalsIgnoreCase("MATCH_BOOST")) {
f.add(new Filter(field, Filter.MATCH_BOOST, functionParamList, parameterList, boostScore));
} else if (function.equalsIgnoreCase("SECTION_BOOST")) {
if (str.length >= 4) {
String[] patList = new String[parameterList.length];
String[] endPatList = new String[parameterList.length];
for (int i = 0; i < parameterList.length; i++) {
String[] range = parameterList[i].split(RANGE_SEPARATOR);
patList[i] = range[0];
if (range.length >= 2)
endPatList[i] = range[1];
else
endPatList[i] = "";
}
f.add(new Filter(field, Filter.SECTION_BOOST, functionParamList, patList, endPatList, boostScore));
} else {
logger.warn("SECTION_BOOST Pattern string or boost score is empty.");
}
} else if (function.equalsIgnoreCase("PREFIX_BOOST")) {
f.add(new Filter(field, Filter.PREFIX_BOOST, functionParamList, parameterList, boostScore));
} else if (function.equalsIgnoreCase("SUFFIX_BOOST")) {
f.add(new Filter(field, Filter.SUFFIX_BOOST, functionParamList, parameterList, boostScore));
} else if (function.equalsIgnoreCase("EXCLUDE")) {
f.add(new Filter(field, Filter.EXCLUDE, functionParamList, parameterList));
} else if (function.equalsIgnoreCase("EXCLUDE_BOOST")) {
f.add(new Filter(field, Filter.EXCLUDE_BOOST, functionParamList, parameterList, boostScore));
} else if (function.equalsIgnoreCase("BOOST")) {
f.add(new Filter(field, Filter.BOOST));
} else if (function.equalsIgnoreCase("GEO_RADIUS")) {
//다중 필드지원.
Filter filter = new Filter(fieldList, Filter.GEO_RADIUS, functionParamList, parameterList);
f.add(filter);
} else if (function.equalsIgnoreCase("GEO_RADIUS_BOOST")) {
//다중 필드지원.
Filter filter = new Filter(fieldList, Filter.GEO_RADIUS_BOOST, functionParamList, parameterList, boostScore);
f.add(filter);
} else {
throw new SearchError(ServerErrorCode.QUERY_SYNTAX_ERROR, "Filter method '" + function + "' is unknown.");
}
}
return f;
}
}