org.apache.lucene.queryparser.classic.PreAnalyzedQueryParser.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.lucene.queryparser.classic.PreAnalyzedQueryParser.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.lucene.queryparser.classic;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedHashSet;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.miscellaneous.SingleTokenTokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.queryparser.classic.QueryNode.NTypes;
import org.apache.lucene.search.Query;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.component.SearchHandler;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.search.PreAnalyzedQParserPlugin;
import org.apache.solr.search.QParser;
import org.apache.solr.search.SyntaxError;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.apache.solr.parser.QueryParser;

public class PreAnalyzedQueryParser extends QParser {

    protected final IndexSchema schema;
    SolrQueryRequest req;

    /***
     * Class Constructor
     * 
     * @param qstr
     * @param localParams
     * @param params
     * @param req
     */
    public PreAnalyzedQueryParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
        super(qstr, localParams, params, req);
        this.schema = this.getReq().getSchema();
        this.req = req;
    }

    /***
     * Transform a single token into its corresponding escaped JSON representation, 
     * i.e. test => \{\"v\"\:\"1\"\,\"tokens\"\:\[\{\"t\"\:\"test\"\}\]\}
     * 
     * @param term
     * @return
     */
    @SuppressWarnings("unchecked")
    private String transformTermToJSON(String term) {
        JSONObject jsonPreAnalizedField = new JSONObject();
        jsonPreAnalizedField.put("v", "1");
        JSONArray tokensArr = new JSONArray();
        JSONObject tokenInfo = new JSONObject();
        tokenInfo.put("t", term.toLowerCase());
        tokensArr.add(tokenInfo);
        jsonPreAnalizedField.put("tokens", tokensArr);
        String qEscJSON = jsonPreAnalizedField.toJSONString().replace("{", "\\{").replace("[", "\\[")
                .replace("\"", "\\\"").replace("}", "\\}").replace("]", "\\]").replace(":", "\\:")
                .replace(",", "\\,");
        return qEscJSON.toString();
    }

    /***
     * Transform a phrase term into its corresponding escaped JSON representation,
     * i.e. "early pionner" => {\"v\"\:\"1\",\"tokens\"\:[{\"t\"\:\"early\"},{\"t\"\:\"pioneer\"}]}
     * 
     * @param phrase
     * @return
     */
    @SuppressWarnings("unchecked")
    private String transformTermToJSONArray(String phrase) {
        String[] terms = phrase.split(" ");
        JSONObject jsonPreAnalizedField = new JSONObject();
        jsonPreAnalizedField.put("v", "1");
        JSONArray tokensArr = new JSONArray();
        for (String term : terms) {
            JSONObject tokenInfo = new JSONObject();
            tokenInfo.put("t", term.toLowerCase());
            tokensArr.add(tokenInfo);

        }
        jsonPreAnalizedField.put("tokens", tokensArr);
        String qEscJSON = jsonPreAnalizedField.toJSONString().replace("\"", "\\\"").replace(":", "\\:");
        return qEscJSON.toString();
    }

    /***
     * Main entry that parses the "q" parameter value from every query,
     * overwrites the parse method from the Solr Query Class.
     * 
     */
    @Override
    public Query parse() throws SyntaxError {

        // Get list of params from request
        NamedList<Object> requestParams = this.params.toNamedList();

        // Getting q param value from request
        String qryJO = requestParams.get("q").toString();

        String finalQry = "";

        if (requestParams.get("queryProcessing") == null) {

            // Get debug parameter from request
            Boolean debugQuery = Boolean.valueOf(params.get("debugQuery"));
            if (debugQuery == null) {
                debugQuery = false;
            }

            // Get lemma exp global param
            Boolean lemmaExp = Boolean.valueOf(params.get("lemma"));
            if (lemmaExp == null) {
                lemmaExp = false;
            }

            // Get synonym exp global param
            Boolean synExp = Boolean.valueOf(params.get("syn"));
            if (synExp == null) {
                synExp = false;
            }

            // Get accent removal global param
            Boolean accRem = Boolean.valueOf(params.get("accRem"));
            if (accRem == null) {
                accRem = false;
            }

            // Get language for the query terms, default to english
            String lang = params.get("language");
            if (lang == null) {
                lang = "en";
            }

            // Special param for lemmatizer testing
            Boolean showLemmas = params.getBool("showLemmas");

            // Store debug messages
            String debugMessage = "<![CDATA[";

            String[] transOut = new String[2];
            if (!qryJO.equals("*:*")) { // validates all docs wildcard query
                transOut = transformParamValue(qryJO, debugQuery, lang, synExp, lemmaExp, accRem);
                finalQry = transOut[0];
            } else { // all docs wildcard query scenario
                finalQry = "*:*";
            }
            // Print final transformed query
            if (debugQuery) {
                debugMessage += transOut[1];
                debugMessage += "After PreAnalyzed transformation->" + finalQry + "]]>";
                System.out.println(debugMessage);
            }

            // Get fq params from request
            List<Object> allFQs = requestParams.getAll("fq");
            requestParams.removeAll("fq");
            // Iterate over all fq params and apply transformations (tokenization, lemmatization, JSON format)
            for (Object fqValue : allFQs) {
                if (fqValue instanceof String[]) {
                    for (String val : (String[]) fqValue) {
                        String newFQ = transformParamValue(val, false, lang, synExp, lemmaExp, accRem)[0];
                        requestParams.add("fq", newFQ);
                    }
                } else {
                    String newFQ = transformParamValue(fqValue.toString(), false, lang, synExp, lemmaExp,
                            accRem)[0];
                    requestParams.add("fq", newFQ);
                }
            }
            if (debugQuery) {
                requestParams.add("queryParserDebugProcess", debugMessage);
            }
            requestParams.add("queryProcessing", "True");
            requestParams.remove("q");
            requestParams.add("q", finalQry);
            this.req.setParams(SolrParams.toSolrParams(requestParams));
        } else {
            finalQry = requestParams.get("q").toString();
        }

        // Redirect the transform query to Solr Query Class
        QueryParser qp = new QueryParser(schema.getDefaultLuceneMatchVersion(), params.get("df"), this);

        Query qry = qp.parse(finalQry);
        return qry;
    }

    public String[] transformParamValue(String qryJO, Boolean debugQuery, String lang, Boolean synExp,
            Boolean lemmaExp, Boolean accRem) {
        String[] out = new String[2];
        String debugMsg = "";

        // Move q value to list of query nodes
        ArrayList<QueryNode> qryL = toQueryList(qryJO, schema);
        if (debugQuery) {
            debugMsg += "NodeList->" + nodeListToString(qryL) + "<br/>";
        }
        // Tokenize recognized term query nodes 
        qryL = tokenizeChildNodes(qryL, lang);
        if (debugQuery) {
            debugMsg += "After tokenization->" + nodeListToString(qryL) + "<br/>";
        }
        // Perfom synonyms expansion of term query nodes
        qryL = synonymExpandChildNodes(qryL, synExp);
        if (debugQuery) {
            debugMsg += "After Synonym expansion->" + nodeListToString(qryL) + "<br/>";
        }
        // Perform lemmatization expansion of term query nodes
        qryL = lemmaExpandChildNodes(qryL, lemmaExp);
        if (debugQuery) {
            debugMsg += "After Lemmatization expansion->" + nodeListToString(qryL) + "<br/>";
        }
        // Perform accent removal to term query nodes
        qryL = accentRemovalChildNodes(qryL, accRem);
        if (debugQuery) {
            debugMsg += "After Accent reduction->" + nodeListToString(qryL) + "<br/>";
        }
        // Transform term query nodes to its corresponding JSON Pre-Analyzed format
        qryL = toJSONPreAnalyzedFormat(qryL);
        String finalQuery = nodeListToString(qryL);

        out[0] = finalQuery;
        if (debugQuery) {
            out[1] = debugMsg;
        }
        return out;
    }

    /***
     * Prints the content of the list of query nodes.
     * @param nodeList
     * @return
     */
    private String nodeListToString(ArrayList<QueryNode> nodeList) {
        String nodeListStr = "";
        String nodeFieldName = "";
        for (QueryNode qryNode : nodeList) {
            if (qryNode.getType().equals(NTypes.TERM)) {
                if (qryNode.getIsPreAnalyzed()) {
                    nodeListStr += nodeFieldName + ":";
                }
            }
            if (qryNode.getType().equals(NTypes.FIELD)) {
                nodeFieldName = qryNode.getData();
                if (!qryNode.getIsPreAnalyzed()) {
                    nodeListStr += nodeFieldName + ":";
                }
            }
            if (qryNode.getIsPhrase()) {
                nodeListStr += "\"" + qryNode.getData() + "\"" + " ";
            } else if (qryNode.getType().equals(NTypes.OPERATOR) && (qryNode.getData().equals("+"))
                    || qryNode.getData().equals("-")) {
                nodeListStr += qryNode.getData();
            } else if ((!qryNode.getType().equals(NTypes.FIELD)) && !qryNode.getData().equals(":")) {
                nodeListStr += qryNode.getData() + " ";
            }
        }
        return nodeListStr.trim();
    }

    /***
     * Expands the term query nodes, if local parameter "syn" is set to true for the specified 
     * field query, i.e. {!syn=true} pre_analyzed_j_2:pixima
     * And adds the expansions as new nodes to the query node list. 
     * @param term
     * @return
     */
    private ArrayList<String> expandSynonyms(String term) {
        ArrayList<String> synonyms = new ArrayList<String>();
        TokenStream ts = PreAnalyzedQParserPlugin.synFactory
                .create(new SingleTokenTokenStream(new Token(term, 0, term.length())));

        CharTermAttribute termAtt = null;
        try {
            while (ts.incrementToken()) {
                termAtt = ts.getAttribute(CharTermAttribute.class);
                if (!termAtt.toString().equals(term)) {
                    synonyms.add(termAtt.toString());
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return synonyms;

    }

    /***
     * Remove accent characters from a token, usign the MappingCharFilterFactory
     * from Solr.
     * @param term
     * @return
     */
    private String removeAccents(String term) {
        List<String> synonyms = new ArrayList<String>();
        Reader ts = PreAnalyzedQParserPlugin.mapCharFactory.create(new StringReader(term));
        StringBuilder actualBuilder = new StringBuilder();
        try {
            // Now consume the actual mapFilter, somewhat randomly:
            while (true) {
                int ch;
                ch = ts.read();
                if (ch == -1) {
                    break;
                }
                actualBuilder.append((char) ch);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return actualBuilder.toString();
    }

    /***
     * Perform tokenization and term analysis using the Solr analyzers defined in the Schema. 
     * @param langCode 
     * @param rawContent 
     * @return
     * */
    private ArrayList<String> getTokensArrayUsingFieldTypes(String langCode, String rawContent) {
        ArrayList<String> tokens = new ArrayList<String>();
        Boolean isPhrase = false;
        if ((rawContent.trim().startsWith("\"")) && (rawContent.trim().endsWith("\""))) {
            isPhrase = true;
        }
        try {
            // Build Solr field type based on language and get the respective analyzer
            String fieldTypeName = "text_" + langCode;
            FieldType fType = schema.getFieldTypeByName(fieldTypeName);
            //Analyzer an = fType.getAnalyzer();
            Analyzer an = fType.getQueryAnalyzer();

            // Apply the analyzer to the content
            TokenStream ts = null;
            ts = an.tokenStream("", new StringReader(rawContent));
            ts.reset();
            CharTermAttribute term = (CharTermAttribute) ts.getAttribute(CharTermAttribute.class);
            int termsCount = 0;
            while (ts.incrementToken()) { // For each detected token
                if ((termsCount == 0) && isPhrase) {
                    tokens.add("\"" + term.toString()); // preserve initial quote
                } else {
                    String tok = term.toString();
                    if (rawContent.contains(tok + "*")) {// preserve trailing wildcard operator
                        tok += "*";
                    }
                    if (rawContent.contains("*" + tok)) {// preserve leading wildcard operator
                        tok = "*" + tok;
                    }
                    tokens.add(tok);
                }
                termsCount++;
            }
            if (isPhrase) { // Adding final quote to last term from phrase
                tokens.set(tokens.size() - 1, tokens.get(tokens.size() - 1) + "\"");
            }
            // Close token stream
            ts.end();
            ts.close();
        } catch (Exception e) {
            // TODO: handle exception
        }

        return tokens;
    }

    /***
     * Moves the q parameter value into a list of query nodes
     * @param str
     * @return
     */
    public ArrayList<QueryNode> toQueryList(String str, IndexSchema schema) {

        // Regular expression for query elements recognition
        /***
         * http://lucene.apache.org/solr/4_6_1/solr-core/org/apache/solr/schema/DateField.html
         * Matches:
         *     1995-12-31T23:59:59Z
         *      1995-12-31T23:59:59.9Z
         *      1995-12-31T23:59:59.99Z
         *      1995-12-31T23:59:59.999Z
         */
        String dateTimeRegEx = "\"?(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(\\.\\d{1}(\\d{1})?(\\d{1})?)?Z\"?";
        Pattern pattern = Pattern.compile(dateTimeRegEx
                + "|[(]|[)]|[\\[]|[\\]]|[\\p{L}|\\p{Pc}|\\p{N}]+|\\p{S}+|[{]|[}]|[\"]|[\"]|[:]|[*]|[?]|[=]|[+]|[-]|.");
        Matcher m = pattern.matcher(str);
        Boolean isOpenLocalParamText = false;
        Boolean isPhrase = false;
        String localParamText = "";
        String tempTerm = "";
        String tempPhrase = "";
        Boolean isWildcardTerm = false;
        Boolean isPreAnalyzed = false;
        ArrayList<QueryNode> nodeList = new ArrayList<QueryNode>();
        String previousToken = "";
        // Iterate over the set of recognized elements from the regular expression defined above
        while (m.find()) {
            String node1 = m.group();
            // if debug mode ON print each recognized element
            /*if (PreAnalyzedQParserPlugin.debugOn) {
                
               }*/
            if (node1.equals("{")) { // Open bracket for local param section
                isOpenLocalParamText = true;
            } else if (node1.equals("}")) {// Close bracket for local param section
                isOpenLocalParamText = false;
            } else if (node1.equals("(") || node1.equals("[")) {// Open parenthesis, add it to the list of nodes 
                nodeList.add(new QueryNode(node1, NTypes.SYMBOL));
            } else if (node1.equals("OR") || node1.equals("AND") || node1.equals("NOT") || node1.equals("+")
                    || node1.equals("-") || (node1.equalsIgnoreCase("to") && !isPreAnalyzed)) {// Boolean operators
                if ((previousToken.trim().isEmpty()) && !isPhrase) {
                    if (!tempTerm.isEmpty()) {// If temporal term buffer not empty, create a node with this value and add it to the list of nodes
                        QueryNode fieldNode = new QueryNode(tempTerm.trim(), NTypes.TERM, isPreAnalyzed);
                        nodeList.add(fieldNode);
                        tempTerm = ""; //clean temporal term buffer
                    } else if (!tempPhrase.isEmpty()) {// If temporal phrase buffer not empty, create a node with this value and add it to the list of nodes
                        QueryNode fieldNode = new QueryNode(tempPhrase.trim(), NTypes.TERM, isPreAnalyzed);
                        fieldNode.setIsPhrase(true); //set phrase flag to true
                        nodeList.add(fieldNode);
                        tempPhrase = ""; //clean temporal phrase buffer
                    }
                    nodeList.add(new QueryNode(node1, NTypes.OPERATOR)); // Add the operator to the list of query nodes
                } else {
                    if (!tempTerm.isEmpty()) {
                        if (previousToken.trim().isEmpty()) {
                            tempTerm = tempTerm + node1;
                        } else {
                            tempTerm = tempTerm.trim() + node1;
                        }
                    } else if (!tempPhrase.isEmpty()) {
                        if (previousToken.trim().isEmpty()) {
                            tempPhrase = tempPhrase + node1;
                        } else {
                            tempPhrase = tempPhrase.trim() + node1;
                        }
                    }
                }
            } else if (node1.equals(")") || node1.equals("]")) { // Close parenthesis, add it to the list of nodes
                if (!tempTerm.isEmpty()) {// If temporal term buffer not empty, create a node with this value and add it to the list of nodes
                    QueryNode fieldNode = new QueryNode(tempTerm.trim(), NTypes.TERM, isPreAnalyzed);
                    nodeList.add(fieldNode);
                    tempTerm = ""; //clean temporal term buffer
                } else if (!tempPhrase.isEmpty()) {
                    QueryNode fieldNode = new QueryNode(tempPhrase.trim(), NTypes.TERM, isPreAnalyzed);
                    fieldNode.setIsPhrase(true); //set phrase flag to true
                    nodeList.add(fieldNode);
                    tempPhrase = ""; //clean temporal phrase buffer
                }
                nodeList.add(new QueryNode(node1, NTypes.SYMBOL)); // Add parenthesis to list of query nodes
            } else if (node1.equals(":") && !isPhrase) { // field name delimiter               
                if (!tempTerm.isEmpty()) { // If temporal term buffer not empty, create a node with this value and add it to the list of nodes as a FIELD type
                    String fieldType = schema.getField(tempTerm.trim()).getType().getClassArg();
                    isPreAnalyzed = false;
                    if (fieldType.contains("solr.PreAnalyzedField")) {
                        isPreAnalyzed = true;
                    }
                    QueryNode fieldNode = new QueryNode(tempTerm.trim(), NTypes.FIELD, isPreAnalyzed);
                    if (!localParamText.isEmpty()) {// Add the local params if any
                        fieldNode.setLocalParams(localParamText);
                    }
                    nodeList.add(fieldNode);
                    tempTerm = "";
                }
                nodeList.add(new QueryNode(node1, NTypes.SYMBOL)); // Add colon to list of query nodes             
            } else if (node1.equals("*") || node1.equals("?") || // Other element like wildcard operators, accented characters and equals
                    node1.equals("=") || node1.matches("\\p{S}")) {
                if (isOpenLocalParamText) {
                    localParamText = localParamText.trim() + node1; // Keep adding to the local params buffer
                } else if (isPhrase) {
                    tempPhrase += node1;
                } else {
                    tempTerm += node1; // Keep adding to the term buffer
                }
                if ((node1.equals("*") || node1.equals("?")) && !isPhrase) {
                    isWildcardTerm = true;
                }
            } else if (node1.trim().isEmpty()) { // Matches white spaces, help delimiting the scope of a wildcard operator to see if 
                // is the end of a term or a part of it, in order to keep adding more element to the term buffer
                if (isWildcardTerm) {
                    isWildcardTerm = false;
                } else if (isPhrase) {
                    tempPhrase += node1;
                } else if (!tempTerm.isEmpty()) {
                    tempTerm += node1;
                }
            } else { // Any other recognized element, like words
                if (isOpenLocalParamText) {
                    localParamText += node1 + " "; // Keep adding to the local params buffer
                } else if (node1.equals("\"")) {
                    if (isPhrase) {
                        isPhrase = false;
                        tempPhrase = tempPhrase.trim(); // Keep adding to the phrase buffer
                    } else {
                        isPhrase = true;
                    }
                } else {
                    if (isPhrase) {
                        tempPhrase += node1; // Keep adding to the phrase buffer
                    } else {
                        if ((tempTerm.trim().endsWith("*")) || // if term buffer ends with wildcard operators or accented characters
                                (tempTerm.trim().endsWith("?")) || (tempTerm.trim().length() > 1)) {
                            if (isWildcardTerm) {
                                tempTerm = tempTerm.trim() + node1 + " "; // Keep adding to the term buffer, character should be part of term, not the end, i.e se?rch
                            } else {
                                tempTerm += node1; // Keep adding to the term buffer, character is the end of the term, i.e. sear*
                            }
                        } else {
                            tempTerm += node1; // // Keep adding to the term buffer
                        }
                    }
                }
            }
            previousToken = node1;
        }

        if (!tempTerm.isEmpty()) { // If there's any term left on buffer, create a node and add it to the list
            QueryNode fieldNode = new QueryNode(tempTerm.trim(), NTypes.TERM, isPreAnalyzed);
            nodeList.add(fieldNode);
            tempTerm = "";
        } else if (!tempPhrase.isEmpty()) { // If there's any phrase left on buffer, create a node and add it to the list
            QueryNode fieldNode = new QueryNode(tempPhrase.trim(), NTypes.TERM, isPreAnalyzed);
            fieldNode.setIsPhrase(true);
            nodeList.add(fieldNode);
            tempPhrase = "";
        }
        return nodeList;
    }

    /***
     * Split the term query nodes into new nodes, depending on the output from the tokenization process 
     *  
     * @param langCode 
     * @param rawContent 
     * @return
     * */
    public ArrayList<QueryNode> tokenizeChildNodes(ArrayList<QueryNode> qryNodeList, String langCode) {

        ArrayList<QueryNode> newQryNodeList = new ArrayList<QueryNode>();
        for (QueryNode qryNode : qryNodeList) {

            if (qryNode.getType().equals(NTypes.TERM) && !qryNode.getIsPhrase() && qryNode.getIsPreAnalyzed()) {
                ArrayList<String> tokens = getTokensArrayUsingFieldTypes(langCode, qryNode.getData());

                //Removing duplicates
                LinkedHashSet hs = new LinkedHashSet();
                hs.addAll(tokens);
                tokens.clear();
                tokens.addAll(hs);

                for (String token : tokens) {
                    newQryNodeList.add(new QueryNode(token, NTypes.TERM, qryNode.getIsPreAnalyzed()));
                }

            } else {
                newQryNodeList.add(qryNode);
            }

        }

        return newQryNodeList;

    }

    public ArrayList<QueryNode> synonymExpandChildNodes(ArrayList<QueryNode> qryNodeList, Boolean synExp) {

        ArrayList<QueryNode> newQryNodeList = new ArrayList<QueryNode>();
        Boolean fieldClauseHasSynExp = false;
        for (QueryNode qryNode : qryNodeList) {
            if (qryNode.getType().equals(NTypes.TERM) && !qryNode.getIsPhrase() && qryNode.getIsPreAnalyzed()) {
                if (fieldClauseHasSynExp) {
                    ArrayList<String> synonyms = expandSynonyms(qryNode.getData());
                    //Removing duplicates
                    LinkedHashSet hs = new LinkedHashSet();
                    hs.addAll(synonyms);
                    synonyms.clear();
                    synonyms.addAll(hs);

                    if (synonyms.size() > 0) {
                        newQryNodeList.add(new QueryNode("(", NTypes.SYMBOL));
                    }
                    newQryNodeList.add(new QueryNode(qryNode.getData(), NTypes.TERM, qryNode.getIsPreAnalyzed()));

                    for (String syn : synonyms) {
                        newQryNodeList.add(new QueryNode(syn, NTypes.TERM, qryNode.getIsPreAnalyzed()));
                    }
                    if (synonyms.size() > 0) {
                        newQryNodeList.add(new QueryNode(")", NTypes.SYMBOL));
                    }
                } else {
                    newQryNodeList.add(new QueryNode(qryNode.getData(), NTypes.TERM, qryNode.getIsPreAnalyzed()));
                }
            } else {
                if (qryNode.getType().equals(NTypes.FIELD)) {
                    if (((qryNode.getLocalParams() != null) && (qryNode.getLocalParams().contains("syn=true")))
                            || synExp) {
                        fieldClauseHasSynExp = true;
                    } else {
                        fieldClauseHasSynExp = false;
                    }
                    newQryNodeList.add(qryNode);
                } else {
                    newQryNodeList.add(qryNode);
                }
            }
        }
        return newQryNodeList;

    }

    public ArrayList<QueryNode> lemmaExpandChildNodes(ArrayList<QueryNode> qryNodeList, Boolean lemmaExp) {

        ArrayList<QueryNode> newQryNodeList = new ArrayList<QueryNode>();
        Boolean fieldClauseHasLemmaExp = false;
        for (QueryNode qryNode : qryNodeList) {
            if (qryNode.getType().equals(NTypes.TERM) && !qryNode.getIsPhrase() && qryNode.getIsPreAnalyzed()) {
                if (fieldClauseHasLemmaExp) {
                    List<String> lemmas = PreAnalyzedQParserPlugin.lemmatizer.expand(qryNode.getData());
                    //Removing duplicates
                    LinkedHashSet hs = new LinkedHashSet();
                    hs.addAll(lemmas);
                    lemmas.clear();
                    lemmas.addAll(hs);

                    if (lemmas.size() > 0) {
                        newQryNodeList.add(new QueryNode("(", NTypes.SYMBOL));
                    }
                    newQryNodeList.add(new QueryNode(qryNode.getData(), NTypes.TERM, qryNode.getIsPreAnalyzed()));

                    for (String lemma : lemmas) {
                        newQryNodeList.add(new QueryNode(lemma, NTypes.TERM, qryNode.getIsPreAnalyzed()));
                    }

                    if (lemmas.size() > 0) {
                        newQryNodeList.add(new QueryNode(")", NTypes.SYMBOL));
                    }
                } else {
                    newQryNodeList.add(new QueryNode(qryNode.getData(), NTypes.TERM, qryNode.getIsPreAnalyzed()));
                }
            } else {
                if (qryNode.getType().equals(NTypes.FIELD)) {
                    if (((qryNode.getLocalParams() != null) && (qryNode.getLocalParams().contains("lemma=true")))
                            || lemmaExp) {
                        fieldClauseHasLemmaExp = true;
                    } else {
                        fieldClauseHasLemmaExp = false;
                    }
                    newQryNodeList.add(qryNode);
                } else {
                    newQryNodeList.add(qryNode);
                }
            }
        }
        return newQryNodeList;
    }

    public ArrayList<QueryNode> accentRemovalChildNodes(ArrayList<QueryNode> qryNodeList, Boolean accRem) {

        ArrayList<QueryNode> newQryNodeList = new ArrayList<QueryNode>();
        Boolean fieldClauseHasAccentRem = false;
        for (QueryNode qryNode : qryNodeList) {
            if (qryNode.getType().equals(NTypes.TERM) && !qryNode.getIsPhrase() && qryNode.getIsPreAnalyzed()) {
                if (fieldClauseHasAccentRem) {
                    newQryNodeList.add(new QueryNode(removeAccents(qryNode.getData()), NTypes.TERM,
                            qryNode.getIsPreAnalyzed()));
                } else {
                    newQryNodeList.add(new QueryNode(qryNode.getData(), NTypes.TERM, qryNode.getIsPreAnalyzed()));
                }
            } else {
                if (qryNode.getType().equals(NTypes.FIELD)) {
                    if (((qryNode.getLocalParams() != null) && (qryNode.getLocalParams().contains("accRed=true")))
                            || accRem) {
                        fieldClauseHasAccentRem = true;
                    } else {
                        fieldClauseHasAccentRem = false;
                    }
                    newQryNodeList.add(qryNode);
                } else {
                    newQryNodeList.add(qryNode);
                }
            }
        }
        return newQryNodeList;
    }

    public ArrayList<QueryNode> toJSONPreAnalyzedFormat(ArrayList<QueryNode> qryNodeList) {

        for (QueryNode qryNode : qryNodeList) {
            if (qryNode.getType().equals(NTypes.TERM)) {
                if (qryNode.getIsPreAnalyzed()) {
                    if (qryNode.getIsPhrase()) {
                        qryNode.setData(transformTermToJSONArray(qryNode.getData()));
                    } else if (!(qryNode.getData().contains("*")) && !(qryNode.getData().contains("?"))) {
                        qryNode.setData(transformTermToJSON(qryNode.getData()));
                    }
                }
            }
        }

        return qryNodeList;
    }
}