com.jaeksoft.searchlib.request.SearchFieldRequest.java Source code

Java tutorial

Introduction

Here is the source code for com.jaeksoft.searchlib.request.SearchFieldRequest.java

Source

/**   
 * License Agreement for OpenSearchServer
 *
 * Copyright (C) 2008-2015 Emmanuel Keller / Jaeksoft
 * 
 * http://www.open-search-server.com
 * 
 * This file is part of OpenSearchServer.
 *
 * OpenSearchServer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 * OpenSearchServer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OpenSearchServer. 
 *  If not, see <http://www.gnu.org/licenses/>.
 **/

package com.jaeksoft.searchlib.request;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.xml.xpath.XPathExpressionException;

import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import com.jaeksoft.searchlib.SearchLibException;
import com.jaeksoft.searchlib.config.Config;
import com.jaeksoft.searchlib.facet.FacetField;
import com.jaeksoft.searchlib.facet.Range;
import com.jaeksoft.searchlib.function.expression.SyntaxError;
import com.jaeksoft.searchlib.query.ParseException;
import com.jaeksoft.searchlib.snippet.SnippetField;
import com.jaeksoft.searchlib.snippet.SnippetFieldList;
import com.jaeksoft.searchlib.util.DomUtils;
import com.jaeksoft.searchlib.util.XPathParser;
import com.jaeksoft.searchlib.util.XmlWriter;
import com.jaeksoft.searchlib.webservice.query.search.SearchFieldQuery.SearchField.Mode;
import com.jaeksoft.searchlib.webservice.query.search.SearchQueryAbstract.Facet.OrderByEnum;
import com.jaeksoft.searchlib.webservice.query.search.SearchQueryAbstract.FragmenterEnum;
import com.jaeksoft.searchlib.webservice.query.search.SearchQueryAbstract.OperatorEnum;

public class SearchFieldRequest extends AbstractLocalSearchRequest
        implements RequestInterfaces.ReturnedFieldInterface, RequestInterfaces.FilterListInterface {

    public final static String SEARCHFIELD_QUERY_NODE_NAME = "query";

    private List<SearchField> searchFields;

    private Map<String, String> queryStringMap;

    public SearchFieldRequest() {
        super(null, RequestTypeEnum.SearchFieldRequest);
    }

    public SearchFieldRequest(Config config) {
        super(config, RequestTypeEnum.SearchFieldRequest);
    }

    @Override
    protected void setDefaultValues() {
        super.setDefaultValues();
        searchFields = new ArrayList<SearchField>(0);
        queryStringMap = null;
    }

    public void setQueryString(String field, String queryString) {
        if (queryStringMap == null)
            queryStringMap = new TreeMap<String, String>();
        if (StringUtils.isEmpty(queryString))
            queryStringMap.remove(field);
        else
            queryStringMap.put(field, queryString);
    }

    public void setQueryString(Map<String, String> queryStringMap) {
        if (this.queryStringMap == null)
            this.queryStringMap = new TreeMap<String, String>();
        else
            this.queryStringMap.clear();
        this.queryStringMap.putAll(queryStringMap);
    }

    final protected String getQueryString(String field) {
        if (queryStringMap == null)
            return null;
        return queryStringMap.get(field);
    }

    @Override
    public void copyFrom(AbstractRequest request) {
        super.copyFrom(request);
        SearchFieldRequest searchFieldRequest = (SearchFieldRequest) request;
        this.searchFields = new ArrayList<SearchField>(0);
        if (searchFieldRequest.searchFields != null)
            for (SearchField searchField : searchFieldRequest.searchFields)
                this.searchFields.add(searchField.clone());
        if (searchFieldRequest.queryStringMap == null)
            this.queryStringMap = null;
        else
            this.queryStringMap = new TreeMap<String, String>(searchFieldRequest.queryStringMap);
    }

    final private static Query getBooleanShouldQuery(Collection<Query> queries) {
        if (queries == null)
            return null;
        switch (queries.size()) {
        case 1:
            return queries.iterator().next();
        default:
            BooleanQuery booleanQuery = new BooleanQuery();
            for (Query query : queries)
                booleanQuery.add(query, Occur.SHOULD);
            return booleanQuery;
        }
    }

    final private static Query getBooleanMustQuery(final Map<Integer, List<Query>> queriesMap) {
        switch (queriesMap.size()) {
        case 0:
            return null;
        case 1:
            return getBooleanShouldQuery(queriesMap.values().iterator().next());
        default:
            BooleanQuery booleanQuery = new BooleanQuery();
            for (Collection<Query> queries : queriesMap.values())
                booleanQuery.add(getBooleanShouldQuery(queries), Occur.MUST);
            return booleanQuery;
        }
    }

    final private Query buildQuery(String queryString, Occur occur, boolean snippet) throws IOException {
        Set<String> fields = config.getSchema().getFieldList().getFieldSet();
        SnippetFieldList snippetFieldList = snippet ? getSnippetFieldList() : null;
        Map<Integer, List<Query>> queriesMap = new TreeMap<Integer, List<Query>>();
        for (SearchField searchField : searchFields) {
            Integer booleanGroup = searchField.getBooleanGroup();
            if (booleanGroup == null)
                booleanGroup = 0;
            List<Query> queries = queriesMap.get(booleanGroup);
            if (queries == null) {
                queries = new ArrayList<Query>(5);
                queriesMap.put(booleanGroup, queries);
            }
            String field = searchField.getField();
            String query = getQueryString(field);
            if (query == null)
                query = queryString;
            if (snippetFieldList != null && snippetFieldList.get(field) == null)
                continue;
            searchField.addQuery(fields, analyzer, query, queries, phraseSlop, occur);
        }
        return getBooleanMustQuery(queriesMap);
    }

    @Override
    protected Query newSnippetQuery(String queryString)
            throws IOException, ParseException, SyntaxError, SearchLibException {
        return buildQuery(queryString, Occur.SHOULD, true);
    }

    private boolean queryIsEmpty(String queryString) {
        if (!StringUtils.isEmpty(queryString))
            return false;
        if (queryStringMap == null)
            return true;
        for (String query : queryStringMap.values())
            if (!StringUtils.isEmpty(query))
                return false;
        return true;
    }

    private Query newComplexQuery(String queryString, Occur occur)
            throws ParseException, SyntaxError, SearchLibException, IOException {
        if (emptyReturnsAll && queryIsEmpty(queryString))
            return new MatchAllDocsQuery();
        return buildQuery(queryString, occur, false);
    }

    @Override
    protected Query newComplexQuery(String queryString)
            throws ParseException, SyntaxError, SearchLibException, IOException {
        Occur occur = defaultOperator == OperatorEnum.AND ? Occur.MUST : Occur.SHOULD;
        return newComplexQuery(queryString, occur);
    }

    @Override
    public void fromXmlConfigNoLock(Config config, XPathParser xpp, Node requestNode)
            throws XPathExpressionException, DOMException, ParseException, InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        super.fromXmlConfigNoLock(config, xpp, requestNode);
        Node fieldQueryNode = DomUtils.getFirstNode(requestNode, SEARCHFIELD_QUERY_NODE_NAME);
        if (fieldQueryNode != null) {
            List<Node> fieldNodeList = DomUtils.getNodes(fieldQueryNode, SearchField.SEARCHFIELD_NODE_NAME);
            if (fieldNodeList != null)
                for (Node fieldNode : fieldNodeList)
                    searchFields.add(new SearchField(fieldNode));
        }
    }

    @Override
    public void writeSubXmlConfig(XmlWriter xmlWriter) throws SAXException {
        xmlWriter.startElement(SEARCHFIELD_QUERY_NODE_NAME);
        for (SearchField searchField : searchFields)
            searchField.writeXmlConfig(xmlWriter);
        xmlWriter.endElement();
    }

    @Override
    public String getInfo() {
        rwl.r.lock();
        try {
            return searchFields.toString();
        } finally {
            rwl.r.unlock();
        }
    }

    public Collection<SearchField> getSearchFields() {
        rwl.r.lock();
        try {
            return searchFields;
        } finally {
            rwl.r.unlock();
        }
    }

    public void add(SearchField searchField) {
        rwl.w.lock();
        try {
            searchFields.add(searchField);
            resetNoLock();
        } finally {
            rwl.w.unlock();
        }
    }

    /**
     * Add a new search field to the request
     * 
     * @param fieldName
     *            The name of the field
     * @param phrase
     *            Activate the phrase search
     * @param boost
     *            Set the boost for the term search
     * @param phraseBoost
     *            Set the boost for the phrase search
     */
    public void addSearchField(String fieldName, Mode mode, double termBoost, double phraseBoost,
            Integer phraseSlop, Integer booleanGroup) {
        add(new SearchField(fieldName, mode, termBoost, phraseBoost, phraseSlop, booleanGroup));
    }

    public void addSearchField(String fieldName, double termBoost) {
        add(new SearchField(fieldName, Mode.PATTERN, termBoost, 1.0, null, null));
    }

    public void remove(SearchField searchField) {
        rwl.w.lock();
        try {
            searchFields.remove(searchField);
            resetNoLock();
        } finally {
            rwl.w.unlock();
        }
    }

    /**
     * Add a snippet field
     * 
     * @param fieldName
     *            The name of the field
     * @param fragmenter
     *            The fragmentation method
     * @param maxSize
     *            The maximum size of the snippet in character
     * @param separator
     *            The string sequence used to highlight keywords
     * @param maxNumber
     *            The maximum number of snippet
     * @throws SearchLibException
     */
    public void addSnippetField(String fieldName, FragmenterEnum fragmenter, int maxSize, String separator,
            int maxNumber) throws SearchLibException {
        SnippetField field = new SnippetField(fieldName);
        field.setFragmenter(fragmenter.className);
        field.setMaxSnippetSize(maxSize);
        field.setSeparator(separator);
        field.setMaxSnippetNumber(maxNumber);
        this.getSnippetFieldList().put(field);
    }

    /**
     * Add facet
     * 
     * @param fieldName
     *            The name of the field
     * @param minCount
     *            The minimum number of document
     * @param multivalued
     *            The field can contains several values
     * @param postCollapsing
     *            The number is calculated after collapsing
     * @param limit
     *            The maximum number of facet to return
     * @param orderBy
     *            The sort order for the facet
     * @param ranges
     *            An optional list of ranges
     */
    public void addFacet(String fieldName, int minCount, boolean multivalued, boolean postCollapsing, Integer limit,
            OrderByEnum orderBy, List<Range> ranges) {
        FacetField facetField = new FacetField(fieldName, minCount, multivalued, postCollapsing, limit, orderBy,
                ranges);
        getFacetFieldList().put(facetField);
    }

}